eiv*_*our 5 c++ gcc initialization constexpr stdoptional
我有以下代码来测试我的 constexpr 可构造惰性类:
#include <optional>
template <class T>
class Lazy
{
using initializer_t = T (*)();
std::optional<T> m_val = std::nullopt;
initializer_t m_initializer;
public:
constexpr Lazy(initializer_t initializer = initializer_t{[] { return T{}; }}) noexcept
: m_initializer{initializer} {}
T& operator*()
{
if (!m_val.has_value()) {
m_val = m_initializer();
}
return *m_val;
}
constexpr T* operator->() { return &(**this); }
};
#include <iostream>
struct A {
int f() { return 10; }
~A()
{
std::cout << "Goodbye A " << (void*)this << std::endl;
}
};
extern Lazy<A> a;
int val = a->f();
Lazy<A> a{[] { return A{}; }};
int main()
{
std::cout << val << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我希望它能打印 10 英寸main。当在 clang-8.0 中编译时,它按预期运行,但是当在 gcc 中(无论是在 8.3 中还是在 trunk 中)编译时,它会导致分段错误。似乎a不是常量初始化,并且在初始化之前a.m_initializer在内部调用 null 。int val = a->f()a
Cppreference表示std::optional<T>可以使用构造函数将其初始化为 std::nullopt constexpr,无论 T 是否可简单破坏。因此,应该在初始化Lazy<A> a{[] { return A{}; }}之前进行常量初始化。int val = a->f();如果我注释掉A::~A,即使使用 gcc 编译,它也会按预期运行。这是 gcc 中的错误,还是我遗漏了什么?
更新:我还发现,如果我创建std::optional<T>一个基类而不是拥有这样的成员,它在 gcc 中可以正常工作。另外,如果我只是将行更改std::optional<T> m_val = std::nullopt;为std::optional<T> m_val;,它就可以正常工作(std::optional<T> m_val{};不起作用)。我实在不明白。
这是 gcc 中的错误,还是我遗漏了什么?
是的,我们可以验证这个错误(程序执行期间的分段错误)在 GCC 9.4 之前仍然可以重现,并且程序从 GCC 10.1 开始运行良好(意味着该错误已修复)。演示: https: //gcc.godbolt.org/z/osWa1no9Y
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |