C++ 转发声明、唯一\u ptr和类内初始值设定项

C++ 转发声明、唯一\u ptr和类内初始值设定项,c++,forward-declaration,unique-ptr,in-class-initialization,C++,Forward Declaration,Unique Ptr,In Class Initialization,我读了很多书,但我的问题更具体 汇编如下: // Compile with $ g++ -std=c++11 -c <filename> #include <memory> class A; // fwd declaration class AUser { AUser(); // defined elsewhere ~AUser(); // defined elsewhere std::unique_ptr<A> m_a; }; //使用$g

我读了很多书,但我的问题更具体

汇编如下:

// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration

class AUser
{
  AUser();  // defined elsewhere
  ~AUser(); // defined elsewhere
  std::unique_ptr<A> m_a;
};
//使用$g++-std=c++11-c编译
#包括
A类;//fwd声明
奥瑟级
{
AUser();//在别处定义
~AUser();//在别处定义
std::唯一的ptr m_a;
};
以下内容不适用:

// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration

class AUser
{
  AUser();  // defined elsewhere
  ~AUser(); // defined elsewhere
  std::unique_ptr<A> m_a{nullptr};
};
//使用$g++-std=c++11-c编译
#包括
A类;//fwd声明
奥瑟级
{
AUser();//在别处定义
~AUser();//在别处定义
std::unique_ptr m_a{nullptr};
};
错误

$ g++ -std=c++11 -c fwd_decl_u_ptr.cpp 
In file included from /usr/include/c++/4.7/memory:86:0,
                 from fwd_decl_u_ptr.cpp:3:
/usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = A]’:
/usr/include/c++/4.7/bits/unique_ptr.h:173:4:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = A; _Dp = std::default_delete<A>]’
fwd_decl_u_ptr.cpp:9:33:   required from here
/usr/include/c++/4.7/bits/unique_ptr.h:63:14: error: invalid application of ‘sizeof’ to incomplete type ‘A’
$g++-std=c++11-c fwd_decl_ptr.cpp
在/usr/include/c++/4.7/memory:86:0中包含的文件中,
从fwd_decl_ptr.cpp:3:
/usr/include/c++/4.7/bits/unique_ptr.h:在“void std::default_delete::operator()(_Tp*)const[with _Tp=A]”的实例化中:
/usr/include/c++/4.7/bits/unique\u ptr.h:173:4:从“std::unique\u ptr::~unique\u ptr()[with _Tp=A;_Dp=std::default\u delete]中需要”
fwd_decl_ptr.cpp:9:33:从这里开始需要
/usr/include/c++/4.7/bits/unique\u ptr.h:63:14:错误:“sizeof”对不完整类型“A”的应用无效

编辑: 据我所知,这里发生的事情是,类内初始值设定项意味着在声明AUser时已经能够初始化
unique\u ptr
。由于类型
unique\u ptr
实际上是
unique\u ptr
,因此能够初始化它意味着能够初始化
default\u delete
。为此,
A
必须完全定义

该推理中的薄弱环节是假设类内初始值设定项意味着在声明类时初始化相应数据成员的能力!这似乎是一个直观的自我证明,因为初始值设定项是声明的一部分。但是,如果我在标准中找到明确说明这一点的内容,我会感到更舒服。否则,我仍然可以想到不需要它的实现解决方案。例如,编译器可以简单地接受初始值设定项表达式,并仅在没有显式给出属性初始化的构造函数中应用它

那么,有谁能让我参考一个标准章节/摘录,它暗示了在第二种情况下对a进行完整定义的必要性?我在标准中没有找到太多关于类内初始值设定项的信息(只发现它们被称为“非静态的括号或相等初始值设定项”)
数据成员),但与此无关。

第二种情况是生成默认析构函数[error],代替
AUser
definition[/error](在这种情况下,它实际上是在处理整个代码之后完成的)。与AUser中构造函数的定义相同

在任何情况下,您都需要在同一编译单元中提供
a
的定义。那么也许像这样的事情会让你满意

#include <memory>

class A;

class AUser
{
  std::unique_ptr<A> m_a;
  AUser();
};


class A
{
  // ...
};


AUser::AUser() 
  : m_a(nullptr)
{ }
#包括
甲级;
奥瑟级
{
std::唯一的ptr m_a;
AUser();
};
甲级
{
// ...
};
AUser::AUser()
:m_a(空ptr)
{ }

第二种情况下的错误是什么?另外:-似乎第一种情况也会导致问题。@KirilKirov它会导致问题,因为您没有定义类A…@KirilKirov:如果您试图在没有定义
A
的情况下生成可执行文件,您显然会遇到问题。但是,如果只编译片段(当然假设
A
的定义将在其他地方提供),则不会编译。我将用错误更新原始帖子。@Everyone-对,对,我的错:)这就是重点,我没有定义任何构造函数,那么为什么要定义析构函数呢?实际上,添加默认值涉及到构造函数的隐含扩展(在创建对象时需要设置该值,并且构造函数对此负责,因此需要向其添加一些代码)。因此,在第二种情况下,您强制重新定义默认构造函数,因此也定义了默认析构函数。--这可能是特定于gcc的,在此时完成,可能另一个编译器将在第一次使用
AUser
之前生成构造函数和析构函数。但无论如何,都需要这样做。对不起,您的论点nt有点让人困惑。我不明白你所说的“添加默认值涉及构造函数的隐含扩展”或“你强制重新定义默认构造函数”是什么意思,尤其是当你说“这可能是特定于gcc的”。使用类内初始值设定项并不等同于定义一个构造函数。事实上,我仍然可以定义默认构造函数,甚至覆盖
m_a
,我还可以定义其他10个使用类内初始值设定项的构造函数。您的回答中没有任何内容表明必须立即证明
AUser
的析构函数在第二种情况下生成。您假设的东西可能有意义,也可能没有意义,但您没有说明编译器为什么必须这样做。它不必这样做。正如我所说,它可以等到第一次使用
AUser
对象。这是对gcc的选择,这可能是(我对gcc的了解不深,不知道这些细节)触发,因为您“接触”了构造函数。您通过添加初始值设定项所做的操作实际上被转换为附加条目
m_a{nullptr}
在除复制构造函数外的所有构造函数的初始化列表中。除非您自己在构造函数中为
m_a
指定一个条目。这使得,在您的情况下,必须使用此条目扩展默认构造函数。