当我向向量添加实例时,为什么会调用我的类的析构函数?
似乎每次我向向量 m_test 添加一个对象时,都会调用析构函数方法。我错过了什么吗?我怎样才能防止这种情况发生?
class TEST
{
public:
TEST();
~TEST();
int * x;
};
TEST::TEST()
{
}
TEST::~TEST()
{
... it is called every time I push_back something to the vector ...
delete x;
}
vector<TEST> m_test;
for (unsigned int i=0; i<5; i++)
{
m_test.push_back(TEST());
}
It seems that every time I add an object to the vector m_test, the destructor method is called. Am I missing something? How can I prevent this from happening?
class TEST
{
public:
TEST();
~TEST();
int * x;
};
TEST::TEST()
{
}
TEST::~TEST()
{
... it is called every time I push_back something to the vector ...
delete x;
}
vector<TEST> m_test;
for (unsigned int i=0; i<5; i++)
{
m_test.push_back(TEST());
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这里的问题是您违反了三法则。您的类有一个析构函数,因此您还需要一个复制构造函数和一个赋值运算符。或者,您不能允许复制您的类(例如,将
T(T const&)
和T& operator=(T const&)
设为私有,或者通过派生自boost::noncopyable
),然后调整向量大小,而不是使用push_back
。在第一种情况下,您可以像平常一样
push_back
您的类。在第二种情况下,语法类似于不做任何这些事情都是一个坏主意,因为您很可能在某些时候遇到双重删除问题 - 即使您认为永远不会复制或分配 < code>TEST 其中
x != nullptr
,明确禁止它会更安全。顺便说一句,如果您有在对象超出范围时应删除的成员指针,请考虑使用智能指针,例如
scoped_ptr
、unique_ptr
和shared_ptr
code> (如果您无法使用 Boost 或 C++11,可能还有auto_ptr
)。The problem here is that you're violating the Rule of Three. Your class has a destructor so you need a copy-constructor and an assignment operator, too. Alternatively, you could not allow your class to be copied (for example by making
T(T const&)
andT& operator=(T const&)
private, or by deriving fromboost::noncopyable
), and then resize the vector instead of usingpush_back
.In the first case, you can just
push_back
your class as you usually would. In the second, the syntax would be something likeNot doing either of these things is a bad idea, as you are very likely to run into double deletion issues at some point -- even if you think you'll never copy or assign a
TEST
wherex != nullptr
, it's much safer to explicitly forbid it.By the way, if you have member pointers that should be deleted when an object goes out of scope, consider using smart pointers like
scoped_ptr
,unique_ptr
andshared_ptr
(and maybeauto_ptr
if you're unable to use Boost or C++11).当您
push_back
时,它不会被调用,当临时对象被销毁时,它会被调用。要在您的示例中修复它:
应该只调用一次。
您的代码正在循环内创建一个临时
TEST
,并在push_back
中使用它,然后当循环结束/重复时该临时文件将超出范围并被销毁。这完全按照预期发生,因为临时TEST
需要清理。如果你想避免这种情况,你需要做任何其他事情,除了为每次推送创建一个临时对象。一种可能的解决方案是:
根据 STL 的优化方式,可能不需要制作多个副本。
如果您在
TEST
类中实现复制构造函数,您也可能可以获得更好的处理效果,例如:这是否合适,或者如何处理它,取决于您的类及其需求,但是您当您定义了自己的常规构造函数和析构函数时,通常应该有一个复制构造函数(否则编译器将生成一个复制构造函数,在这种情况下,它将导致复制并挂起指向
x
的指针)。It's not called when you
push_back
, it's called when the temporary is destroyed.To fix it in your example:
Should only call it once.
Your code is creating a temporary
TEST
within the loop, using it inpush_back
, then that temporary is going out of scope when the loop ends/repeats and getting destroyed. That occurs exactly as it should, since the temporaryTEST
needs cleaned up.If you want to avoid that, you need to do anything else but make a temporary object for each push. One potential solution is to:
Depending on how your STL is optimized, this may not need to make multiple copies.
You may also be able to get better handling if you implement a copy constructor in your
TEST
class, like:Whether this is appropriate, or how you handle it, depends on your class and its needs, but you should typically have a copy constructor when you have defined your own regular constructor and destructor (otherwise the compiler will generate one, and in this case, it will result in copied and hanging pointers to
x
).为了避免破坏临时和以避免复制构造函数,请考虑使用vector::resize 或 vector::emplace_back。下面是使用
emplace_back
的示例:矢量元素将就地构建,无需复制。当vt被销毁时,每个向量元素也被自动销毁。
需要 c++0x(与 gnu 一起使用
-std=c++0x
)。#include
当然也是必需的。如果未使用默认构造函数(例如,如果
TEST::x
是引用而不是指针),只需在对emplace_back()
的调用中添加参数即可如下所示:所示的
reserve()
是可选的,但可确保在开始构造向量元素之前有足够的空间可用。To avoid destruction of a temporary and to avoid copy constructors, consider using vector::resize or vector::emplace_back. Here's an example using
emplace_back
:The vector element will be constructed in-place without the need to copy. When vt is destroyed, each vector element is automatically destroyed.
c++0x is required (use
-std=c++0x
with gnu).#include <vector>
is of course also required.If a default constructor is not used (for example, if the
TEST::x
was a reference instead of a pointer), simply add arguements to the call toemplace_back()
as follows:The
reserve()
shown is optional but insures that sufficient space is available before beginning to construct vector elements.vector.push_back()
将给定对象复制到其存储区域中。您在push_back()
调用中构造的临时对象在复制后立即被销毁,这就是您所看到的。有些编译器可能能够优化这个副本,但你的编译器显然不能。vector.push_back()
copies the given object into its storage area. The temporary object you're constructing in thepush_back()
call is destroyed immediately after being copied, and that's what you're seeing. Some compilers may be able to optimize this copy away, but yours apparently can't.在
m_test.push_back(TEST());
中,TEST()将创建一个临时变量。当向量将其复制到自己的内存后,临时变量将被破坏。你可以这样做:
In
m_test.push_back(TEST());
, TEST() will create an temporary variable. After the vector copy it to its own memory, the temporary variable is destructed.You may do like this:
析构函数不仅仅被临时变量调用。
当向量的容量发生变化时,析构函数也会被调用。
这种情况经常发生在非常小的向量上,而在大向量上则较少发生。
这会导致:
新的内存分配(大小基于增长指标,而不仅仅是大小+1)
将旧元素复制到新分配中
销毁旧向量中的元素
释放旧向量内存。
将新项目的构造复制到新向量的末尾。
请参阅此处的第三个答案:
当我push_back到向量时调用析构函数
The destructor is not only being called for the temporary variable.
The destructor will also get called when the capacity of the vector changes.
This happens often on very small vectors, less so on large vectors.
This causes:
A new allocation of memory (size based on a growth metric, not just size+1)
Copy of the old elements into the new allocation
Destruction of the elements in the old vector
Freeing of the old vector memory.
Copy construction of the new item onto the end of the new new vector.
See the third answer here:
Destructor is called when I push_back to the vector