我最近了解了unique_ptr
的用法,希望我可以摆脱STL容器按值存储性质所固有的复制开销。但是我遇到了一个非常奇怪的行为,无法弄清楚原因。
struct LargeObj
{
int id;
LargeObj(int _id) : id(_id)
{
cout << "[" << this << "] is constructed\n";
}
~LargeObj()
{
cout << "[" << this << "] is destroyed\n";
}
// Simulate huge data size
int data[10000];
};
int main(int argc, char **argv)
{
vector<unique_ptr<LargeObj>> store_by_pointer;
for (int i = 0; i < 10; i++)
{
LargeObj obj(i);
store_by_pointer.push_back(unique_ptr<LargeObj>(&obj));
}
for (auto ite = store_by_pointer.begin(); ite != store_by_pointer.end(); ite++)
{
printf("ID: %d\n", (*ite)->id);
}
return 0;
}
输出如下
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
[00000000001A6180] is constructed
[00000000001A6180] is destroyed
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
ID: 9
我的问题是为什么每个push_back
替换它前面的所有项目,从而使所有对象与被推送的最后一个对象相同,在这种情况下是带有ID的LargeObj
9。
答案 0 :(得分:0)
您应该从unique_ptr
返回的指针构造new
,而不是堆栈变量的地址 - 或者甚至更好,使用make_unique
。您还应确保始终如一地使用std::cout
或始终printf
。再试一次:
#include <vector>
#include <memory>
#include <iostream>
struct LargeObj
{
int id;
LargeObj(int _id) : id(_id)
{
std::cout << "[" << this << "] is constructed\n";
}
~LargeObj()
{
std::cout << "[" << this << "] is destroyed\n";
}
// Simulate huge data size
int data[10000];
};
int main(int argc, char **argv)
{
std::vector<std::unique_ptr<LargeObj>> store_by_pointer;
for (int i = 0; i < 10; i++)
{
store_by_pointer.push_back(std::make_unique<LargeObj>(i));
}
for (const auto& ptr : store_by_pointer)
{
std::cout << "ID: " << ptr->id << "\n";
}
return 0;
}
你的问题是只有一个LargeObj
(在堆栈上)。每次循环循环时,同一块内存在堆栈上构造为LargeObj
,并且在循环结束时,LargeObj
被销毁(析构函数被调用)。在循环之后,您打印出(非)随机位堆栈的内容;严格来说,这是未定义的行为,任何都可能发生。但是,打印出您存储的最后一个ID的值并不是特别令人惊讶的结果。
预测未定义的行为将会发生什么:调试时这是一件很有用的事情(这样你就可以理解代码的行为)了,但编写代码依赖极其是危险的在上面。它会改变 - 以最奇怪和无益的方式可以想象。
另请注意,我已经包含了标题,因此它变为Minimal, Complete, and Verifiable Example(并使用std::
并使用迭代for循环。