unique_ptr 的模板实例化和 pimpl 习语
Template instantiations and pimpl idiom with unique_ptr
我读了 Howard Hinnant (Is std::unique_ptr<T> required to know the full definition of T?) and then this answer (How is a template instantiated?) 的这个回答,我只是在想。如果你有这样的 class
class Something {
Something();
~Something();
class Impl;
std::unique_ptr<Impl> impl;
};
unique_ptr
将在编译 class 时实例化(我可以从上面的其他答案中看出)。那为什么以后不定义 class Impl
就可以了?实例化不需要 Impl
的析构函数存在吗?
注意以下是为了澄清我上面的问题。
我的想法是,当编译器检查 class Something
的定义时。它将看到嵌套的 class Impl
的声明,然后它会看到 unique_ptr<Impl>
的声明,然后在那个位置。它将用 Impl
实例化模板 unique_ptr
。该实例化代码将包含对 Impl
的析构函数的调用。由于此时我们的代码包含对不完整 class 的析构函数的调用,上面的代码如何安全?
The accepted answer to the first question 包含 table 个用例,其中需要 Impl
的完整定义。
在您的情况下,编译器隐式生成以下成员函数:
- 复制构造函数
- 移动构造函数
- 复制赋值运算符
- 移动赋值运算符。
他们都需要Impl
的完整定义。
如果您显式声明这些函数并在 Impl
的完整定义可用的地方定义它们,您就没问题。
更新
It will see the declaration of the nested class Impl
and then it will see the declaration of the unique_ptr<Impl>
, and at that point. It will instantiate the template unique_ptr
with Impl
.
这只是在一定程度上是正确的。不是所有unique_ptr
的成员函数都会在那个时候被实例化。
And that instantiated code will contain a call to the destructor of Impl
.
不正确。只有在需要时,编译器才会生成(或实例化)std::unique_ptr<Impl>
的析构函数的代码。那个地方就是Something
.
的析构函数
Something
的析构函数将需要 std::unique_ptr<Impl>
的析构函数。
std::unique_ptr<Impl>
的析构函数需要 Impl
.
的完整定义
换句话说,Impl
的完整定义必须对Something
的析构函数可见。
PS
有关模板实例化的更多信息,请访问 Template instantiation details of GCC and MS compilers。
如果你尝试编译上面的代码并创建一个Something的对象,它会给出一个错误信息:
Semantic issue:
memory:2523:27: Invalid application of 'sizeof' to an incomplete type
'Something::Impl'
简而言之,代码是不可编译的,在这种情况下没有必要考虑安全问题。
我读了 Howard Hinnant (Is std::unique_ptr<T> required to know the full definition of T?) and then this answer (How is a template instantiated?) 的这个回答,我只是在想。如果你有这样的 class
class Something {
Something();
~Something();
class Impl;
std::unique_ptr<Impl> impl;
};
unique_ptr
将在编译 class 时实例化(我可以从上面的其他答案中看出)。那为什么以后不定义 class Impl
就可以了?实例化不需要 Impl
的析构函数存在吗?
注意以下是为了澄清我上面的问题。
我的想法是,当编译器检查 class Something
的定义时。它将看到嵌套的 class Impl
的声明,然后它会看到 unique_ptr<Impl>
的声明,然后在那个位置。它将用 Impl
实例化模板 unique_ptr
。该实例化代码将包含对 Impl
的析构函数的调用。由于此时我们的代码包含对不完整 class 的析构函数的调用,上面的代码如何安全?
The accepted answer to the first question 包含 table 个用例,其中需要 Impl
的完整定义。
在您的情况下,编译器隐式生成以下成员函数:
- 复制构造函数
- 移动构造函数
- 复制赋值运算符
- 移动赋值运算符。
他们都需要Impl
的完整定义。
如果您显式声明这些函数并在 Impl
的完整定义可用的地方定义它们,您就没问题。
更新
It will see the declaration of the nested class
Impl
and then it will see the declaration of theunique_ptr<Impl>
, and at that point. It will instantiate the templateunique_ptr
withImpl
.
这只是在一定程度上是正确的。不是所有unique_ptr
的成员函数都会在那个时候被实例化。
And that instantiated code will contain a call to the destructor of
Impl
.
不正确。只有在需要时,编译器才会生成(或实例化)std::unique_ptr<Impl>
的析构函数的代码。那个地方就是Something
.
Something
的析构函数将需要 std::unique_ptr<Impl>
的析构函数。
std::unique_ptr<Impl>
的析构函数需要 Impl
.
换句话说,Impl
的完整定义必须对Something
的析构函数可见。
PS
有关模板实例化的更多信息,请访问 Template instantiation details of GCC and MS compilers。
如果你尝试编译上面的代码并创建一个Something的对象,它会给出一个错误信息:
Semantic issue:
memory:2523:27: Invalid application of 'sizeof' to an incomplete type
'Something::Impl'
简而言之,代码是不可编译的,在这种情况下没有必要考虑安全问题。