将新对象元素推送到std::vector
的正确方法是什么?我希望数据在向量中分配。这会将对象newradio
复制到向量中,然后在超出范围(例如,不在堆栈中)时删除newradio
吗?
vector<Radio> m_radios;
Radio newradio(radioNum);
m_radios.push_back(newradio);
然后当我释放包含m_radios
的对象时,它会释放向量分配的所有内存吗?
答案 0 :(得分:34)
std::vector
管理自己的记忆。这意味着,当调用向量的析构函数时,向量所占用的内存将被释放。 std::vector
在删除对象时也会调用对象的析构函数(通过erase
,pop_back
,clear
或向量的析构函数。)
执行此操作时:
Radio newradio(radioNum);
m_radios.push_back(newradio);
您将newradio
(使用Radio
的复制构造函数创建)的副本添加到向量中。当newradio
超出范围时,它将被销毁,并且当从向量中移除副本时(例如任何对象),副本将被销毁。
这一点非常重要:std::vector
只存储对象的副本,这意味着该对象必须具有有意义的复制构造函数(和赋值运算符,但这是另一个问题)。如果你有一个指针向量,那么指针本身将被复制,而不是指向它。请注意,此行为对于每个标准容器都是相同的(例如std::list
或std::set
)。
根据经验,如果你没有使用指针,那么你不必担心自己释放内存。
在C ++ 11中,大多数标准容器(包括vector
)都有一个emplace_back
方法,可以在容器的末尾构建一个到位对象。它需要一堆参数并调用最能匹配这些参数的构造函数(如果不存在这样的构造函数,则会失败),使用所述构造函数在容器的末尾创建没有任何副本的对象。因此,上面的代码可以改写为:
m_radios.emplace_back(radioNum); // construct a Radio in place,
// passing radioNum as the constructor argument
同样在C ++ 11中,容器通常是移动识别,因此它们不再需要对象可复制:如果它们可移动,则容器将移动其内容根据需要(例如在重新分配期间)。如果要复制矢量,仍然需要可复制类型。
答案 1 :(得分:4)
push_back()
将在向量中存储其参数的副本。只要Radio
实现了正确的值语义,就不会有问题。
答案 2 :(得分:1)
是的,推送newRadio会将Radio对象的副本推送到向量中。您也不需要释放向量,因为它只是本地的,因此一旦超出其范围就会被销毁。例如,如果你写了
vector<Radio> *m_radios = new vector<Radio>();
然后你必须通过手动调用vector析构函数来释放内存。
答案 3 :(得分:1)
试试这个:
#include<iostream.h>
#include<vector.h>
class base
{
int i;
public:
base(int z=0){i=z;cout<<"okk constructor "<<i<<" called\n";}
base(const base& b1){i=b1.i;cout<<"copy constructor "<<i<<" called\n";}
void display(){cout<<" val is "<<i<<" \n";}
~base(){cout<<"destructor of "<<i<<" base called\n";}
};
int main()
{
cout<<"before anything\n";
vector<base> basev;
base baseobj1(1);
base baseobj2(2);
base baseobj3(3);
base baseobj4(4);
base baseobj5(5);
base baseobj6(6);
base baseobj7(7);
base baseobj8(8);
base baseobj9(9);
base baseobj10(10);
basev.push_back(baseobj1);
cout<<"second push back\n";
basev.push_back(baseobj2);
cout<<"third push back\n";
basev.push_back(baseobj3);
cout<<"fourth push back\n";
basev.push_back(baseobj4);
cout<<"fifth push back\n";
basev.push_back(baseobj5);
cout<<"sixth push back\n";
basev.push_back(baseobj6);
cout<<"seventh push back\n";
basev.push_back(baseobj7);
cout<<"eighth push back\n";
basev.push_back(baseobj8);
cout<<"ninth push back\n";
basev.push_back(baseobj9);
cout<<"10th push back\n";
basev.push_back(baseobj10);
cout<<"after all push back\n";
cout<<"before clear\n";
basev.clear();
cout<<"after clear\n";
}
输出:
before anything
okk constructor 1 called
okk constructor 2 called
okk constructor 3 called
okk constructor 4 called
okk constructor 5 called
okk constructor 6 called
okk constructor 7 called
okk constructor 8 called
okk constructor 9 called
okk constructor 10 called
copy constructor 1 called
second push back
copy constructor 1 called
copy constructor 2 called
destructor of 1 base called
third push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
destructor of 1 base called
destructor of 2 base called
fourth push back
copy constructor 4 called
fifth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
sixth push back
copy constructor 6 called
seventh push back
copy constructor 7 called
eighth push back
copy constructor 8 called
ninth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
copy constructor 6 called
copy constructor 7 called
copy constructor 8 called
copy constructor 9 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
10th push back
copy constructor 10 called
after all push back
before clear
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
destructor of 9 base called
destructor of 10 base called
after clear
destructor of 10 base called
destructor of 9 base called
destructor of 8 base called
destructor of 7 base called
destructor of 6 base called
destructor of 5 base called
destructor of 4 base called
destructor of 3 base called
destructor of 2 base called
destructor of 1 base called
答案 4 :(得分:0)
是的,radioNum
将复制到m_radios
。只要你在newradio.~Radio();
发生时(超出范围)你没有释放指针,那就没问题了。如果m_radios
或子类使用指针,则需要切换到smart pointers(shared_ptr
)。
当m_radios
超出范围时,会自动调用析构函数,并释放所有std::vector
所有的东西。
答案 5 :(得分:0)
除了通过调用复制构造函数使用push_back
验证对象是否已复制到容器中的其他答案之外,您还可以记住添加了emplace_back
的新功能。 {1}}。
调用c++0x
允许您绕过任何临时对象的创建,并直接在容器内就地构建对象。 emplace_back
是一个varardic模板函数,它接受你传递给对象构造函数的参数,所以在这种情况下:
emplace_back
不会创造任何中间临时工。如果您的对象复制成本很高,这可能会有所帮助。
希望这有帮助。
答案 6 :(得分:0)
默认情况下,std :: vector使用基础类的复制构造函数来管理内存本身。因此,它的作用有点像向量元素是一个局部变量(当向量超出范围时,元素被破坏)。
当你不想要这种行为时,你可以使用指针向量或者使用boost :: ptr_vector。