意外覆盖" unique_ptr"在向量中

时间:2016-09-26 07:34:28

标签: vector unique-ptr

我最近了解了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。

1 个答案:

答案 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循环。