移动后,唯一指针仍然保持对象

Bab*_*ger 2 c++ pointers

我正在阅读一些有关智能指针如何在C++中工作的教程,但我仍然坚持我尝试的第一个:唯一指针.我正在遵循维基百科,cppreferencecplusplus的指导原则.我已经看过这个答案了.如果我理解正确的话,唯一的指针应该是对某个存储单元/块具有所有权的唯一指针.这意味着只有唯一指针(应该)指向该单元格而没有其他指针.从维基百科,他们使用以下代码作为示例:

std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; //Compile error.
std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is rendered invalid.

p3.reset(); //Deletes the memory.
p1.reset(); //Does nothing.
Run Code Online (Sandbox Code Playgroud)

直到第二行,当我测试它时,这对我来说很好.但是,在第一个唯一指针移动到第二个唯一指针后,我发现两个指针都可以访问同一个对象.我认为整个想法是让第一个指针变得毫无用处可以这么说?我期望一个空指针或一些未确定的结果.我运行的代码:

class Figure {
public:
    Figure() {}

    void three() {
        cout << "three" << endl;
    }

};

class SubFig : public Figure {
public:
    void printA() {
        cout << "printed a" << endl;
    }
};

int main()
{
    unique_ptr<SubFig> testing (new SubFig());
    testing->three();
    unique_ptr<SubFig> testing2 = move(testing);
    cout << "ok" << endl;
    int t;
    cin >> t; // used to halt execution so I can verify everything works up til here
    testing->three(); // why is this not throwing a runtime error?
}
Run Code Online (Sandbox Code Playgroud)

这里,testing已被移动到testing2,所以我很惊讶地发现,我仍然可以调用该方法three()testing.

此外,调用reset()似乎并没有像它所说的那样删除内存.当我修改main方法成为:

int main()
{
    unique_ptr<SubFig> testing (new SubFig());
    testing->three();
    unique_ptr<SubFig> testing2 = move(testing);
    cout << "ok" << endl;
    int t;
    cin >> t;
    testing.reset(); // normally this should have no effect since the pointer should be invalid, but I added it anyway
    testing2.reset();
    testing2->three();
}
Run Code Online (Sandbox Code Playgroud)

在这里,我希望three()不会工作,testing2因为维基百科的例子提到应该通过重置删除内存.我还打印出印有仿佛一切都很好.这对我来说似乎很奇怪.

所以任何人都可以向我解释原因:

  • 从一个唯一指针移动到另一个唯一指针不会使第一个指针无效?
  • 重置实际上不会删除内存?reset()调用时实际发生了什么?

Gal*_*lik 8

之后,std::move()原来的指针testing设置为nullptr

std::unique_ptr不检查空访问以引发运行时错误的可能原因是每次使用std::unique_ptr. 通过没有运行时检查,编译器能够std::unique_ptr完全优化调用,使其与使用原始指针一样有效。

您在调用 时没有崩溃的原因nullptr可能是因为您调用的函数没有访问(不存在的)对象的内存。但这是未定义的行为,所以任何事情都可能发生。


小智 6

本质上,您通过空指针调用成员函数:

int main()
{
    SubFig* testing = nullptr;
    testing->three();
}
Run Code Online (Sandbox Code Playgroud)

......这是未定义的行为.

从20.8.1类模板unique_ptr(N4296)

4此外,根据请求,您可以将所有权转移到另一个唯一指针u2.完成此类转移后,以下 后置条件成立:

  • u2.p等于转移前,
  • up等于nullptr,和
  • 如果预转移ud维持状态,则此类状态已转移到u2.d.

(强调我的)