在C风格的指针值是垃圾,但智能指针是正确的

时间:2018-03-24 08:38:10

标签: c++ memory

我有那个c ++代码

#include <iostream>
#include <vector>
#include <memory>

struct Foo{
    int* a;

    Foo(std::vector<int> vec)
    {
        a = &(vec.front());
    }
};

struct Bar {
    std::unique_ptr<int> a;

    Bar(std::vector<int> vec)
    {
        a = std::make_unique<int>(vec.front());
    }
};

int main() {
    std::vector<int> vec = {42};
    Foo foo(vec);
    Bar bar(vec);
    // returns 0, but should 42
    std::cout << *foo.a << std::endl;
    // but this returns 42
    std::cout << *bar.a << std::endl;

    return 0;
}

为什么* foo.a会返回0而不是42?我做错了什么?

4 个答案:

答案 0 :(得分:2)

将行Foo(std::vector<int> vec)更改为Foo(std::vector<int>& vec),它会正常工作。见here working

问题是vec是一个局部变量,一旦函数调用返回就不再有效。

答案 1 :(得分:1)

  

为什么*foo.a会返回0,而不是42?

因为未定义的行为意味着您的程序可以执行所有操作。它可能会崩溃,它可能会打印42,它可能会打印0,它可能无法打印。 C ++语言规范没有规定将要发生的事情。

未定义的行为是由尝试访问已经销毁的对象的指针引起的。在Foo(std::vector<int> vec)中,您会获得向量的本地副本。构造函数结束时,副本将被销毁。事后a不能用于任何事情。你甚至无法安全地将它与另一个指针或nullptr进行比较,更不用说取消它了!所有你能用它做的就是设置一个新的指针值。

*foo.a试图读取指针值。在这一刻,发生了未定义的行为。

智能指针版本没有未定义的行为,因为std::make_unique<int>创建了整数的动态分配的副本。该副本由a内部管理,仅在a本身被销毁时销毁。

答案 2 :(得分:0)

问题是您按值传递矢量,创建内容的副本。请注意,在执行构造函数后,此向量会立即超出范围。这样,你的指针就会指向任何东西。通常这会使程序崩溃,但在某些环境中它只是给出了&#39; 0&#39;。

要解决您的问题,请通过引用或const引用传递向量。有关按引用传递的详细信息,另请参阅this link

答案 3 :(得分:-3)

两种变体都是错误的。您将Vector的副本传递给构造函数,获取指向第一个元素的指针,并在构造函数返回后销毁该副本,使指针无效。 unique_ptr会自动销毁你给它的指针,vector也会破坏它的内存,所以你在第二个例子中释放了两次相同的内存。