当我向向量添加实例时,为什么会调用我的类的析构函数?

发布于 2025-01-06 19:58:48 字数 389 浏览 0 评论 0原文

似乎每次我向向量 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

别靠近我心 2025-01-13 19:58:48

这里的问题是您违反了三法则。您的类有一个析构函数,因此您还需要一个复制构造函数和一个赋值运算符。或者,您不能允许复制您的类(例如,将 T(T const&)T& operator=(T const&) 设为私有,或者通过派生自 boost::noncopyable),然后调整向量大小,而不是使用 push_back

在第一种情况下,您可以像平常一样push_back您的类。在第二种情况下,语法类似于

std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.

不做任何这些事情都是一个坏主意,因为您很可能在某些时候遇到双重删除问题 - 即使您认为永远不会复制或分配 < code>TEST 其中 x != nullptr,明确禁止它会更安全。

顺便说一句,如果您有在对象超出范围时应删除的成员指针,请考虑使用智能指针,例如 scoped_ptrunique_ptrshared_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&) and T& operator=(T const&) private, or by deriving from boost::noncopyable), and then resize the vector instead of using push_back.

In the first case, you can just push_back your class as you usually would. In the second, the syntax would be something like

std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.

Not 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 where x != 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 and shared_ptr (and maybe auto_ptr if you're unable to use Boost or C++11).

冷情妓 2025-01-13 19:58:48

当您push_back时,它不会被调用,当临时对象被销毁时,它会被调用

要在您的示例中修复它:

TEST test;
for (int i = 0; i < 5; ++i)
{
    m_test.push_back(test);
}

应该只调用一次。

您的代码正在循环内创建一个临时 TEST,并在 push_back 中使用它,然后当循环结束/重复时该临时文件将超出范围并被销毁。这完全按照预期发生,因为临时 TEST 需要清理。

如果你想避免这种情况,你需要做任何其他事情,除了为每次推送创建一个临时对象。一种可能的解决方案是:

vector<TEST> m_test(5); // Note reserving space in the vector for 5 objects

std::fill(m_test.begin(), m_test.end(), TEST()); // Fill the vector with the default ctor

根据 STL 的优化方式,可能不需要制作多个副本。

如果您在 TEST 类中实现复制构造函数,您也可能可以获得更好的处理效果,例如:

TEST::TEST(const TEST & other)
{
    x = new int(*other.x); // Not entirely safe, but the simplest copy ctor for this example.
}

这是否合适,或者如何处理它,取决于您的类及其需求,但是您当您定义了自己的常规构造函数和析构函数时,通常应该有一个复制构造函数(否则编译器将生成一个复制构造函数,在这种情况下,它将导致复制并挂起指向 x 的指针)。

It's not called when you push_back, it's called when the temporary is destroyed.

To fix it in your example:

TEST test;
for (int i = 0; i < 5; ++i)
{
    m_test.push_back(test);
}

Should only call it once.

Your code is creating a temporary TEST within the loop, using it in push_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 temporary TEST 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:

vector<TEST> m_test(5); // Note reserving space in the vector for 5 objects

std::fill(m_test.begin(), m_test.end(), TEST()); // Fill the vector with the default ctor

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:

TEST::TEST(const TEST & other)
{
    x = new int(*other.x); // Not entirely safe, but the simplest copy ctor for this example.
}

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).

哭泣的笑容 2025-01-13 19:58:48

为了避免破坏临时以避免复制构造函数,请考虑使用vector::resizevector::emplace_back。下面是使用 emplace_back 的示例:

vector<TEST> m_test;
m_test.reserve(5); 
for ( uint i=0; i<5; i++ ) 
{
    m_test.emplace_back();
}

矢量元素将就地构建,无需复制。当vt被销毁时,每个向量元素也被自动销毁。

需要 c++0x(与 gnu 一起使用 -std=c++0x)。 #include 当然也是必需的。

如果未使用默认构造函数(例如,如果 TEST::x 是引用而不是指针),只需在对 emplace_back() 的调用中添加参数即可如下所示:

class TEST
{
public:
    TEST( int & arg) : x(arg) {;} // no default constructor
    int & x; // reference instead of a pointer.
};

. . . 

int someInt;

vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ ) {
    m_test.emplace_back( someInt ); // TEST constructor args added here.
}

所示的 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:

vector<TEST> m_test;
m_test.reserve(5); 
for ( uint i=0; i<5; i++ ) 
{
    m_test.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 to emplace_back() as follows:

class TEST
{
public:
    TEST( int & arg) : x(arg) {;} // no default constructor
    int & x; // reference instead of a pointer.
};

. . . 

int someInt;

vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ ) {
    m_test.emplace_back( someInt ); // TEST constructor args added here.
}

The reserve() shown is optional but insures that sufficient space is available before beginning to construct vector elements.

画中仙 2025-01-13 19:58:48

vector.push_back() 将给定对象复制到其存储区域中。您在 push_back() 调用中构造的临时对象在复制后立即被销毁,这就是您所看到的。有些编译器可能能够优化这个副本,但你的编译器显然不能。

vector.push_back() copies the given object into its storage area. The temporary object you're constructing in the push_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.

风蛊 2025-01-13 19:58:48

m_test.push_back(TEST());中,TEST()将创建一个临时变量。当向量将其复制到自己的内存后,临时变量将被破坏。

你可以这样做:

vector<TEST> m_test(5, 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:

vector<TEST> m_test(5, TEST());
青朷 2025-01-13 19:58:48

析构函数不仅仅被临时变量调用。

当向量的容量发生变化时,析构函数也会被调用。

这种情况经常发生在非常小的向量上,而在大向量上则较少发生。

这会导致:

新的内存分配(大小基于增长指标,而不仅仅是大小+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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文