C++ 当我不';我不想这样

C++ 当我不';我不想这样,c++,class,oop,destructor,C++,Class,Oop,Destructor,在作用域结束之前调用我创建的类的析构函数。我认为当我向向量中添加另一个元素时,它与向量中的重新分配有关。我如何超越这个问题?我希望仅当对象到达代码中作用域的末尾时才调用析构函数 #include <string> #include <iostream> #include <vector> using namespace std; class A { public: ~A() { cout << "destructor called\n"

在作用域结束之前调用我创建的类的析构函数。我认为当我向向量中添加另一个元素时,它与向量中的重新分配有关。我如何超越这个问题?我希望仅当对象到达代码中作用域的末尾时才调用析构函数

#include <string>
#include <iostream>
#include <vector>

using namespace std;

class A
{
public:
    ~A() { cout << "destructor called\n"; }
};

int main ()
{
    A one, two;

    vector<A> vec;
    cout << "push_back one" << endl;
    vec.push_back(one);
    cout << "push_back two" << endl;
    vec.push_back(two);
    //destructor gets called here
    system("pause");
    return 0;
} //while i want it to be called here
#包括
#包括
#包括
使用名称空间std;
甲级
{
公众:

~A(){cout代码中的打印输出并没有向您显示完整的情况:为不同的对象调用析构函数

看看这段修改后的代码,我添加了地址的打印输出,并记录了一些其他关键位置,比如赋值运算符和复制构造函数的调用

#include <string>
#include <iostream>
#include <vector>

using namespace std;

class A
{
public:
    A() {cout << "constructed " << (void*)this << "\n";}
    A(const A& a) {cout << "copied " << (void*)(&a) << " to " << (void*)this << "\n"; }
    A& operator =(const A& a) {cout << "assigned " << (void*)(&a) << " to " << (void*)this << "\n"; }
    ~A() { cout << "destructor called for " << (void*)this << "\n"; }
};

int main ()
{
    A one, two;

    vector<A> vec;
    cout << "push_back one" << endl;
    vec.push_back(one);
    cout << "push_back two" << endl;
    vec.push_back(two);
    //destructor gets called here
    return 0;
}

您可以看到对象
one
two
0xbff229b2
0xbff229b3
)直到结束时才被销毁,当它们超出范围时。当向量调整大小时,它们的副本会被销毁。

正如注释所示,您应该使用
std::vector::reserve(size\t)

您看到的是实现定义的。大多数实现在增长时大约是保留分配大小的两倍。这是为了避免在大小增长时进行大量分配和复制

保留只是向集合建议您将需要n个元素。如果实现选择接受请求,它将重新分配现有值,并将其移动/复制到新分配中,新分配的大小足以容纳您请求的元素数。现在您可以在不花费高昂费用的重新分配的情况下推回。正确保留可以当您知道最终大小时,可以在调整容器大小时为您节省许多重新分配的时间

在这种情况下保留将避免重新调整大小,以及破坏您看到的临时文件

您可能会看到析构函数,因为集合正在调整大小。当您第二次向后推时,它会重新分配


如果对象不可被破坏,则应考虑另一个集合类型或存储位置,因为其当前形式的程序依赖于实现定义的行为(即,标准的向量规范不能保证您需要)。

< P>根据C++标准Pur.23.3.6:

向量具有特定的容量,即

向量在不需要重新分配的情况下可以容纳的元素总数

当您
推回
一个额外的元素时,这会有效地将容器大小增加一个,这

如果新容量大于旧容量,则会导致重新分配

重新分配意味着您正在取消分配(即销毁)向量中的元素,然后再次分配(即构造)它们

请注意,在您的情况下,
A
的原始
one
two
实例不会被销毁,而是存储在向量中的副本会被销毁

但是程序员需要更加小心地使用引用和迭代器,因为

重新分配使序列中引用元素的所有引用、指针和迭代器无效

正如其他人提到的,
reserve()
将有助于防止这种情况,因为

在调用reserve()后发生的插入期间,不得进行重新分配 直到插入会使向量的大小大于capacity()的值为止


使用vector上的reserve来防止重新分配。你必须调用。我正在寻找一种不同的解决方法。调用reserve()对我来说听起来像是个骗局。我想完全理解这个问题。也许可以使类a“更智能”通过向它添加一些代码?与你的问题无关,但和是我最讨厌的两个。如果向量的缓冲区空间不足,需要分配一个新的缓冲区,则旧缓冲区的内容必须被销毁。没有办法解决这个问题。有没有办法知道何时只有原始对象被销毁?@Pilpel不完全是-它什么时候被销毁对于调用析构函数,在堆栈和复制对象上创建的对象之间没有什么不同的C++。接近它的一种方法是在对象中存储一个标志,该标志将向析构函数发出信号,表明它是一个“原始”对象,并且不在复制构造函数或赋值操作符中复制该标志。
constructed 0xbff229b2
constructed 0xbff229b3
push_back one
copied 0xbff229b2 to 0x970c008
push_back two
copied 0xbff229b3 to 0x970c019
copied 0x970c008 to 0x970c018
destructor called for 0x970c008
destructor called for 0x970c018
destructor called for 0x970c019
destructor called for 0xbff229b3
destructor called for 0xbff229b2