C++23 中 unique_ptr 的 nullptr init 规则是否发生变化?

Ben*_*uch 13 c++ unique-ptr visual-c++ language-lawyer c++23

此代码在 C++20 模式下使用 VS 2022 中的 MSVC 进行编译。它在 C++23 模式下失败。( /std:c++latest)

#include <memory>

struct A;

struct B {
    B();
    ~B();

    std::unique_ptr<A> ptr{nullptr};
};

int main(){
    B b;
}
Run Code Online (Sandbox Code Playgroud)

当前版本的 GCC 和 clang 在 C++23 模式下接受此代码。

编译器资源管理器上的实时代码

C++23 模式下的 MSVC:

#include <memory>

struct A;

struct B {
    B();
    ~B();

    std::unique_ptr<A> ptr{nullptr};
};

int main(){
    B b;
}
Run Code Online (Sandbox Code Playgroud)

微软回答我(尚未公开),新行为是由于constexpr std::unique_ptrC++23 模式造成的,他们只是遵循这个标准。

这是正确的吗?GCC 和 clang 在 C++23 模式下接受此代码是错误的吗?


我将对这里发生的情况添加更多解释,因为一些评论表明这并不明显。

std::unique_ptr<A>这里调用了的构造函数。它不会调用不完整类型的构造函数A,因为它是用nullptr. 这部分对于 C++23 模式下的 MSVC 来说似乎很好。

这里没有调用 的函数。它是从另一个源代码文件中定义的析构函数调用的,其中是完整类型。这适用于 GCC 和 clang。它还可以在 C++20 模式下与 MSVC 一起使用。在 C++23 模式下,MSVC 抱怨它无法实例化 的析构函数,因为这里不是完整的类型。std::unique_ptr<A>BAstd::unique_ptr<A>A

在我看来,析构函数永远不应该从此代码单元实例化。

另一方面,MSVC 支持告诉我,这对于 C++23 有效,因为std::unique_ptr现在是constexpr.


GitHub 用户Frederick-vs-ja将问题简化为一个最小的示例:

C:/data/msvc/14.38.33133/include\memory(3169): error C2027: use of undefined type 'A'
<source>(3): note: see declaration of 'A'
C:/data/msvc/14.38.33133/include\memory(3169): note: the template instantiation context (the oldest one first) is
<source>(9): note: see reference to class template instantiation 'std::unique_ptr<A,std::default_delete<A>>' being compiled
C:/data/msvc/14.38.33133/include\memory(3205): note: see reference to class template instantiation 'std::default_delete<A>' being compiled
C:/data/msvc/14.38.33133/include\memory(3168): note: while compiling class template member function 'void std::default_delete<A>::operator ()(_Ty *) noexcept const'
        with
        [
            _Ty=A
        ]
C:/data/msvc/14.38.33133/include\memory(3280): note: see the first reference to 'std::default_delete<A>::operator ()' in 'std::unique_ptr<A,std::default_delete<A>>::~unique_ptr'
C:/data/msvc/14.38.33133/include\memory(3169): error C2338: static_assert failed: 'can't delete an incomplete type'
C:/data/msvc/14.38.33133/include\memory(3170): warning C4150: deletion of pointer to incomplete type 'A'; no destructor called
<source>(3): note: see declaration of 'A'
Run Code Online (Sandbox Code Playgroud)

实时代码:案例a案例b案例c。非常感谢!案例a是我原来的案例。

正如江安指出的,如果你使用template <typename=void> struct ClasssoClass成为模板,那么clang是唯一拒绝代码的。居住


编辑 1:我已向 MS STL 提交了错误报告:

当前的讨论是这是一个编译器错误,而不是库错误。

编辑 2:我已向 GCC 提交了错误报告:

GCC 无法编译std::unique_ptr<A> ptr = {nullptr};。(注意=

编辑 3:我已向 clang 提交了错误报告: