gpt4 book ai didi

c++ - 为什么 clang 使用 libstdc++ 删除包含 std::optional 的类型上的显式默认构造函数?

转载 作者:行者123 更新时间:2023-12-03 10:03:23 27 4
gpt4 key购买 nike

考虑以下带有 std::optional 的结构包含绝对具有“正常”默认构造函数的类型。

#include <optional>
#include <string>

struct Foo
{
Foo() = default;
const std::optional<std::string> m_value;
};

bool function()
{
Foo foo;
return bool(foo.m_value);
}
使用 clang 9 编译以下内容(使用系统默认的 libstdc++ ,对于它的 gcc 8)会给出一个意外警告:
<source>:6:5: warning: explicitly defaulted default constructor is implicitly deleted [-Wdefaulted-function-deleted]
Foo() = default;
^
<source>:7:38: note: default constructor of 'Foo' is implicitly deleted because field 'm_value' of const-qualified type 'const std::optional<std::string>' (aka 'const optional<basic_string<char> >') would not be initialized
const std::optional<std::string> m_value;
^
Foo foo; 也有硬错误因为它使用了所述删除的构造函数。
  • 删除 Foo() = default;构造函数给出相同的结果。
  • 将其替换为 Foo() {}作品!
  • 删除所有构造函数并初始化 fooFoo foo{};作品!
  • 显式初始化成员为 const std::optional<std::string> m_value{};作品!
  • 删除 const从成员作品! (但意思不一样)
  • 将 clang 9 与 -stdlib=libc++ 一起使用作品!
  • 使用 gcc 8.3(仍然使用 libstdc++ )有效!

  • 我已阅读 std::optional - construct empty with {} or std::nullopt?这似乎表明 libstdc++ = default 的实现选择 std::optional 的构造函数很可能是罪魁祸首。但是,在这个问题上,关注的是一种方法与另一种方法的效率问题。在这种情况下,这似乎是一个正确的问题。
    (我怀疑 How can std::chrono::duration::duration() be constexpr? 的答案将成为这里故事的一部分。)
    我在编译器资源管理器上看到相同的行为: https://gcc.godbolt.org/z/Yj1o5P
    比较可选和非可选的简单结构 std::string (在非工作配置中):
    struct Foo { const std::optional<std::string> m_value; };
    auto f1() { Foo f; return f.m_value; } // Fails: call to implicitly deleted constructor.

    struct Bar { const std::string m_value; };
    auto f2() { Bar b; return b.m_value; } // Works.
    这是 libstdc++ 中的错误吗? ? clang 和 libstdc++ 之间是否存在混合意图和假设? ?
    当然,意图不可能是我可以拥有一个带有 const std::string 的结构。但我不能拥有带有 const std::optional<std::string> 的结构除非我写了一个构造函数?
    (在实际情况下,你也会有额外的构造函数。因此,首先是 = default() 构造函数的动机。那个,和clang-tidy。)
    编辑:这是示例( Compiler Explorer )的扩展版本,显示了在“纯 clang”、“纯 gcc”中工作的类似示例,但在混合“clang+libstdc++”中失败。这个稍微大一点的例子仍然是人为的,但暗示了为什么人们可能想要真正拥有这样一个默认的构造函数。
    struct Foo
    {
    Foo() = default; // Implicitly deleted?!
    explicit Foo(std::string arg) : m_value{std::move(arg)} {}
    const auto& get() const noexcept { return m_value; }
    private:
    const std::optional<std::string> m_value;
    };

    // Maybe return an empty or a full Foo.
    auto function(bool flag, std::string x)
    {
    Foo foo1;
    Foo foo2{x};
    return flag ? foo1 : foo2;
    }

    最佳答案

    这是以下组合:

  • 标准中的规范不足;
  • 一个次优的库实现;和
  • 一个编译器错误。

  • 首先,标准没有规定是否为默认 optional.ctor允许的实现是将其定义为默认值:
    constexpr optional() noexcept = default;
    ^^^^^^^^^ OK?
    请注意 functions.within.classes对复制/移动构造函数、赋值运算符和非虚拟析构函数的问题给出了肯定的回答,但没有提到默认构造函数。
    这很重要,因为它会影响程序的正确性;假设 optional具有近似于以下的数据成员:
    template<class T>
    class optional {
    alignas(T) byte buf[sizeof(T)]; // no NSDMI
    bool engaged = false;
    // ...
    };
    然后自 buf如果 optional 的默认构造函数,则是缺少默认成员初始值设定项的直接非变体非静态数据成员被定义为默认值,因此不是用户提供的, optional不是 const-default-constructible等等 optional<A> const a;是畸形的。
    因此,库定义 optional 的默认构造函数是一个坏主意。作为默认值,不仅因为这个原因,还因为它使一个值初始化 optional<B> b{};执行不必要的工作,因为它必须零初始化 buf ,正如观察到的 std::optional - construct empty with {} or std::nullopt? - 特别参见 this answer . libstdc++ 已在 this commit 中修复,它将包含在 gcc 的下一个版本中,假设是 gcc 11。
    最后,这是 gcc 中的一个错误,它允许 const 使用非 const-default-constructible 类型。没有默认构造函数定义为 defaulted 的类类型的默认成员初始值设定项的非静态数据成员; clang 拒绝它是正确的。一个 reduced testcase是:
    struct S {
    S() = default;
    int const i;
    };
    在您的情况下,最好的解决方法是提供 NSDMI:
    const std::optional<std::string> m_value = std::nullopt;
    ^^^^^^^^^^^^^^
    或者(虽然我更喜欢前者,因为它在 Clang/libstdc++ 下 gives better codegen):
    const std::optional<std::string> m_value = {};
    ^^^^
    你也可以考虑给 Foo用户定义的默认构造函数;此 results in better codegen在 gcc 下(不是将缓冲区归零,而是仅将 engaged 成员设置为 false ),这要归功于可能是相关的编译器错误。

    关于c++ - 为什么 clang 使用 libstdc++ 删除包含 std::optional 的类型上的显式默认构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63624014/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com