The following code compiles with MSVC (/permissive-) and fails to compile with GCC/Clang for m_ptr1 and m_ptr2.
#include <memory>
struct ForwardDeclared;
class A {
public:
explicit A();
~A();
private:
std::unique_ptr<ForwardDeclared> m_ptr1 = nullptr; // not ok
std::unique_ptr<ForwardDeclared> m_ptr2 {std::unique_ptr<ForwardDeclared>{}}; // not ok
std::unique_ptr<ForwardDeclared> m_ptr3 {nullptr}; // ok
std::unique_ptr<ForwardDeclared> m_ptr4; // ok
};
int main() {
A a;
return 0;
}
My understanding is that the =
sign results in copy initialization, however, thanks to copy elision I would expect m_ptr2
would still be initialized without failure.
Why does m_ptr2
require a destructor of ForwardDeclared and are Clang/GCC correct for this? (Bonus: Is it correct to conclude that m_ptr1 is incorrectly accepted by MSVC?)
EDIT: Logged a bug with clang about this issue: https://github.com/llvm/llvm-project/issues/54291
CWG 2426 refers specifically to a destructor being potentially invoked in the cases:
Section 11.9.2 [class.expl.init] is not mentioned in the above list, and thus seems not to be in the destructor is potentially invoked case.
Which raises a question whether indeed as @Fedor argues, MSVC is wrong and GCC and Clang are correct. On the face of it, it seems to be the opposite.
Note that cppreference on copy elision doesn't argue that all cases of copy elision require the destructor to be visible, it refers only to the case of: