C++ 标量删除析构函数问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17840579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
scalar deleting destructor issue
提问by user1558064
I can't figure out why I get error for the code below.
我不明白为什么下面的代码会出错。
The instances of object A will be pushed into a vector
(vectorA.push_back(A a)
) continuously. So sometimes, vectorA
needs to be reallocated; the destructor will be called, which is where the destructor of A
gets called, then the error message appears.
对象 A 的实例将被连续推入 a vector
( vectorA.push_back(A a)
)。所以有时,vectorA
需要重新分配;析构函数将被调用,这是调用析构函数的地方A
,然后出现错误消息。
class A
{
long filePos;
union {
Recording* recording;
UINT64 timeStamp;
};
public:
inline A(long fpos, UINT64 ts) : filePos(fpos), timeStamp(ts) {}
~A()
{
if (getDetailedType() == RECORDING_TYPE)
if (recording)
delete recording; // error: scalar deleting destructor ???
}
inline short getDetailedType() const { return (short)(timeStamp % 5); }
A(const A& edi)
{
filePos = edi.filePos;
if (getDetailedType() == RECORDING_INFO)
recording = edi.recording;
else
timeStamp = edi.timeStamp;
}
}
class Recording : protected RECORDINGS
{
UINT64 timestamp;
float scalar;
public:
~Recording() // with or without this dtor, got same error
{
}
inline Recording()
{
timestamp = 0;
scalar = 2.0;
time = 0;
rate = 30;
type = 1;
side = 1;
}
}
typedef struct
{
UINT32 time;
float rate;
int type;
int side;
} RECORDINGS;
回答by Chad
Your copy constructor does a shallow copy. So, now you have two objects that both have the same recording
pointer.
您的复制构造函数执行浅复制。所以,现在你有两个对象,它们都具有相同的recording
指针。
You should either do a deep copy, or ensure the ownership is properly transferred (by using something like std::unique_ptr<Recording>
if C++11
is available.
您应该进行深度复制,或者确保所有权正确转移(通过使用std::unique_ptr<Recording>
if C++11
is available 之类的东西。
See This question on the difference between deep and shallow copies.
请参阅有关深拷贝和浅拷贝之间区别的这个问题。
Let's look at some examples:
让我们看一些例子:
class ABadCopyingClass
{
public:
ABadCopyingClass()
{
a_ = new int(5);
}
~ABadCopyingClass()
{
delete a_;
}
private:
int* a_;
};
The above class is bad because the default copy constructor and assignment operator will perform a shallow copy, and lead to two objects both thinking that they own the underlying a_
object. When one of them goes out of scope, the a_
will be deleted, and the other one will be left with a dangling pointer that will eventually lead to a crash.
上面的类很糟糕,因为默认的复制构造函数和赋值运算符会执行浅拷贝,并导致两个对象都认为它们拥有底层a_
对象。当其中一个超出范围时,a_
将被删除,而另一个将留下一个悬空指针,最终将导致崩溃。
class ABetterCopyingClass
{
public:
ABetterCopyingClass()
a_(new int(5))
{
}
ABetterCopyingClass(const ABetterCopyingClass& r)
{
a_ = new int(*r.a_);
}
ABetterCopyingClass& operator=(const ABetterCopyingClass& r)
{
// in the case of reassignment...
delete a_;
a_ = new int(*r.a_);
return *this;
}
~ABetterCopyingClass()
{
delete a_;
}
private:
int* a_;
};
This class improved our situation a little (note, that the normal error checking is left out in this simple example). Now the copy constructor and assignment operator properly perform the necessary deep copying. The drawback here is the amount of boilerplate code we had to add -- it's easy to get that wrong.
这个类稍微改善了我们的情况(注意,在这个简单的例子中省略了正常的错误检查)。现在复制构造函数和赋值运算符正确地执行了必要的深度复制。这里的缺点是我们必须添加大量的样板代码——很容易出错。
class ACannonicalCopyingClass
{
public:
ACannonicalCopyingClass()
: a_(new int(5))
{
}
ACannonicalCopyingClass(ACannonicalCopyingClass&& moved_from)
{
a_ = std::move(moved_from.a_);
}
private:
std::unique_ptr<int> a_;
};
This example (C++11 only) is even better. We've removed a significant amount of boilerplate code, however the semantics here are a bit different. Instead of deep copying, we get in this case transfer of ownership of the underlying a_
object.
这个例子(仅限 C++11)更好。我们删除了大量样板代码,但是这里的语义有点不同。在这种情况下,我们得到了底层a_
对象所有权的转移,而不是深度复制。
The easiest version (C++11 only) to implement is the version that provides shared ownership of the underlying a_
object. This is the version that is most similar to your provided example, with the added bonus that it does notcause a crash.
最容易实现的版本(仅限 C++11)是提供底层a_
对象共享所有权的版本。这是与您提供的示例最相似的版本,还有一个额外的好处,即它不会导致崩溃。
class ASharedCopyingClass
{
public:
ASharedCopyingClass()
: a_(std::make_shared<int>(5))
{
}
private:
std::shared_ptr<int> a_;
};
This version can be copied at will, and the underlying a_
object will happily be reference counted. The last copy to go out of scope will set the reference count to 0
, which will trigger the memory deallocation.
这个版本可以随意复制,底层a_
对象会愉快地进行引用计数。最后一个超出范围的副本会将引用计数设置为0
,这将触发内存释放。
回答by Mark B
My psychic debugging skills tell me that you forgot to implement a copy constructor for A
which then results in a double deletion of a Recording
when the copy is destroyed.
我的通灵调试技巧告诉我,你忘记实现一个复制构造函数,当副本被销毁时,A
它会导致重复删除 a Recording
。
The growth of the vector would trigger the copy-destroy pairs.
向量的增长将触发复制破坏对。