关于 pimpl 语法
About the pimpl syntax
我对 pimpl 语法中使用的 C++ 用法有疑问。
首先,为什么不用把pimpl( new impl )
写成pimpl( new my_class::impl )
其次,为什么new impl
的生命周期延长了,即使它是一个临时对象?
//my_class.h
class my_class {
// ... all public and protected stuff goes here ...
private:
class impl; unique_ptr<impl> pimpl; // opaque type here
}
// my_class.cpp
class my_class::impl { // defined privately here
// ... all private data and functions: all of these
// can now change without recompiling callers ...
};
my_class::my_class(): pimpl( new impl )
{
// ... set impl values ...
}
首先: 在您的构造函数中,表达式 new impl
确实是一个临时对象,但它会立即传递给 pimpl
成员,这不是一个暂时的。 std::unique_ptr
类型存储传递给它的指针并保留它直到它被销毁或移动。在 my_class
对象被销毁之前,成员不会被销毁。
此外,考虑使用 std::make_unique
而不是 new
。
其次:你不用写my_class::impl
因为你是my_class
的成员函数,所以名字解析看起来not only at namespace scope but also at class scope.所以,impl
可以解决
First, why is it not necessary to write pimpl( new impl ) as pimpl( new my_class::impl )
范围。定义构造函数后,您就在 class 的副本中,因此 name lookup 可以毫无问题地找到它。
Second, why is the lifetime of new impl extended even though it is a temporary object?
您正在将临时指针作为 std::unique_ptr<impl>
的构造函数参数传递给 std::unique_ptr<impl>
,因此值被字段 pimpl
使用。 impl
值不是临时的,因为它是在堆上创建的,其生命周期的控制权已传递给智能指针。
额外:
您在 header 中完成了 using namespace std;
(唯一可以在 unique_ptr
之前跳过 std::
的情况)!这是大错误,不要这样做。这将对包括此 header 在内的所有来源产生危险影响。因此,您可能会遇到符号歧义错误。
即使在 cpp 文件中有 using namespace std;
也是 considered a bad practice。
new impl
不是临时变量,因为它不是变量。
是一个表达式,
- 在您的
my_class::pimpl
对象成员构造期间进行评估,
- 它的副作用是创建一个
impl
对象(它的生命周期是受控的,不是自动的,因为它不是局部自动变量),
- 其中 returns 指向新创建的 anonymous
impl
对象的指针。
表达式用作正在构造的 my_class
对象的 pimpl
成员的初始化器,因此返回的指针作为初始化值传递给 pimpl
并被存储在里面。这允许您的 my_class
对象控制 impl
对象的生命周期。
pimpl
指针变量的生命周期显然与其拥有 my_class
对象的生命周期相同,但是指向 impl
对象的生命周期取决于您的 my_class
逻辑:
- 它可能会保留它直到它自己结束并在它自己销毁时将其删除,
- 可以
replace()
随意搭配另一个
- 或
release()
pimpl
、delete
impl
对象并在不再需要时无需任何对象即可工作...
- 它甚至可能释放对象而不是删除它,例如将所有权转移给另一个对象——或者只是放弃它,这会导致内存泄漏(这是通常是一个严重的错误!)
我对 pimpl 语法中使用的 C++ 用法有疑问。
首先,为什么不用把pimpl( new impl )
写成pimpl( new my_class::impl )
其次,为什么new impl
的生命周期延长了,即使它是一个临时对象?
//my_class.h
class my_class {
// ... all public and protected stuff goes here ...
private:
class impl; unique_ptr<impl> pimpl; // opaque type here
}
// my_class.cpp
class my_class::impl { // defined privately here
// ... all private data and functions: all of these
// can now change without recompiling callers ...
};
my_class::my_class(): pimpl( new impl )
{
// ... set impl values ...
}
首先: 在您的构造函数中,表达式 new impl
确实是一个临时对象,但它会立即传递给 pimpl
成员,这不是一个暂时的。 std::unique_ptr
类型存储传递给它的指针并保留它直到它被销毁或移动。在 my_class
对象被销毁之前,成员不会被销毁。
此外,考虑使用 std::make_unique
而不是 new
。
其次:你不用写my_class::impl
因为你是my_class
的成员函数,所以名字解析看起来not only at namespace scope but also at class scope.所以,impl
可以解决
First, why is it not necessary to write pimpl( new impl ) as pimpl( new my_class::impl )
范围。定义构造函数后,您就在 class 的副本中,因此 name lookup 可以毫无问题地找到它。
Second, why is the lifetime of new impl extended even though it is a temporary object?
您正在将临时指针作为 std::unique_ptr<impl>
的构造函数参数传递给 std::unique_ptr<impl>
,因此值被字段 pimpl
使用。 impl
值不是临时的,因为它是在堆上创建的,其生命周期的控制权已传递给智能指针。
额外:
您在 header 中完成了 using namespace std;
(唯一可以在 unique_ptr
之前跳过 std::
的情况)!这是大错误,不要这样做。这将对包括此 header 在内的所有来源产生危险影响。因此,您可能会遇到符号歧义错误。
即使在 cpp 文件中有 using namespace std;
也是 considered a bad practice。
new impl
不是临时变量,因为它不是变量。
是一个表达式,
- 在您的
my_class::pimpl
对象成员构造期间进行评估, - 它的副作用是创建一个
impl
对象(它的生命周期是受控的,不是自动的,因为它不是局部自动变量), - 其中 returns 指向新创建的 anonymous
impl
对象的指针。
表达式用作正在构造的 my_class
对象的 pimpl
成员的初始化器,因此返回的指针作为初始化值传递给 pimpl
并被存储在里面。这允许您的 my_class
对象控制 impl
对象的生命周期。
pimpl
指针变量的生命周期显然与其拥有 my_class
对象的生命周期相同,但是指向 impl
对象的生命周期取决于您的 my_class
逻辑:
- 它可能会保留它直到它自己结束并在它自己销毁时将其删除,
- 可以
replace()
随意搭配另一个 - 或
release()
pimpl
、delete
impl
对象并在不再需要时无需任何对象即可工作... - 它甚至可能释放对象而不是删除它,例如将所有权转移给另一个对象——或者只是放弃它,这会导致内存泄漏(这是通常是一个严重的错误!)