You*_*ouk 2 c++ destructor parameter-passing
在 Herbert Schildt 的《C++ IT-Tutorial》一书中,第 9 章第 368 页,指出了以下问题:
即使您按值将对象传递给函数(在这种情况下,理论上应该隔离和保护传递的对象),该对象仍然可能会被更改甚至被副作用破坏。当在函数内调用对象的析构函数以删除对象的本地副本时,可能会发生这种情况。
该段落是为了鼓励使用复制构造函数而编写的。
不幸的是,尽管书中的大多数其他问题都用简单的示例进行了记录,但我找不到重现此行为的最小示例。你能推荐一个吗?
发生这种情况通常是因为程序员没有遵循三、五或零的规则。
当您按值传递对象时,编译器将创建代码来进行浅复制。以具有指针成员变量的对象为例。复制对象将复制指针,而不是它指向的数据。当副本被破坏时,它的delete内存就会被破坏,这意味着原始对象中的指针不再有效,因为它仍然指向现在已删除的内存。
举个简单的例子:
struct S
{
// Some data
};
struct Bad
{
S* pointer;
Bad()
: pointer{ new S } // Create an object, and initialize the pointer
{}
~Bad()
{
delete pointer;
}
};
void f(Bad copy)
{
// Do something...
}
int main()
{
Bad original;
f(original);
}
Run Code Online (Sandbox Code Playgroud)
调用该函数时,会创建f该对象的副本。original该副本将具有 的运行时的生命周期f。当生命周期结束时,copy它的析构函数将被调用。但由于 和original都copy指向同一个S对象,因此 in 的指针original将变得无效。
这个问题可以通过多种方式解决。第一个也是最简单的方法是创建一个Bad复制构造函数,它创建自己的 副本S,因此它独立于原始副本。
一个更好的解决方案是使用类似的东西std::shared_ptr<S>。这通常用于标记所有权,但也可以在这里工作。
更好的解决方案是S根本不将对象作为指针,因为编译器生成的复制构造函数将确保S也创建该对象的副本。尽管这可能并非在所有情况下都是可能的(想想多态性)。
但我认为最好的解决方案是通过引用传递对象:
void f(Bad const& reference) { ... }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
180 次 |
| 最近记录: |