首页 > 解决方案 > 为什么在 std::move 函数之后对象仍然存在?

问题描述

我对 std::move 函数有疑问。请参考以下代码:

#include <iostream>
#include <memory>

using namespace std;

class CPointer {
public:
    CPointer(double a, double b)
    {
        m_dX = a;
        m_dY = b;
    }

    ~CPointer()
    {
        m_dX = m_dY = 0;
    }


    double getX() const
    {return m_dX;}

    double getY() const
    {return m_dY;}

private:
    double m_dX;
    double m_dY;
};

class CContainer 
{
public:
    CContainer(CPointer* p)
    {
        m_p = p;
    }

    ~CContainer()
    {
        m_p = nullptr;
    }

    CPointer* getP() const
    {return m_p;}

private:
    CPointer* m_p;

};


class CBigContainer
{
public:
    CBigContainer(CContainer* p)
    {
        m_p = p;
    }
    ~CBigContainer()
    {
        m_p = nullptr;
    }
    CContainer* getP() const
    {return m_p;}

private:
    CContainer* m_p;
};

int main()
{
    CPointer* pPointer = new CPointer(150,360);

    cout << "1.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";

    std::shared_ptr<CContainer> spContainer = std::make_shared<CContainer>(pPointer);

    cout << "2.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";

    std::shared_ptr<CBigContainer> spBigContainer = std::make_shared<CBigContainer>(std::move(spContainer.get())); //<--- std::move here

    cout << "3.) " << spBigContainer->getP()->getP()->getX() << " , " << spBigContainer->getP()->getP()->getY() << "\n";
    cout << "4.) " << spContainer->getP()->getX() << " , " << spContainer->getP()->getY() << "\n";
    cout << "5.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";

    return 0;
}

这是结果:

在此处输入图像描述

我的问题是,我正在使用 std::move

std::shared_ptr<CBigContainer> spBigContainer = std::make_shared<CBigContainer>(std::move(spContainer.get()));

所以我期望spContainer在代码行之后不能使用,因为智能指针内部的对象被删除了。但它仍然可以正常工作。在这种情况下,不使用 std::move 似乎没有什么不同。

你能详细给我解释一下吗?非常感谢你。

标签: c++c++11rvalue

解决方案


所以我期望 spContainer 在代码行之后不能使用,因为智能指针内部的对象被删除了。

您的代码实际上从未请求任何移动操作。智能指针是一个红鲱鱼,在这种情况下你可以看到相同的行为:

CContainer a(pPointer);

CBigContainer b(std::move(&a));

最后一行是一样的,CBigContainer b( &a );因为 的构造函数CBigContainer接受一个指针,而基本类型(包括指针)的移动操作的行为是保持源不变。

您的代码使CBigContainer对象指向CContainer对象(后者仍由智能指针管理)。这是一个坏主意,因为如果您随后释放CContainer智能指针,则CBigContainer指向它的 ' 指针将悬空。

你的CContainerCBigContainer对象持有指向其他对象的原始指针。将这些对象放在智能指针中不会改变这一点。


如果您不清楚,这是两件不同的事情:

  • 移出智能指针。
  • 移出由智能指针管理的对象。

第一个将使智能指针为空。第二个使智能指针处于活动状态并管理处于移动后状态的对象。

下面是一个将移出 spContainer 的代码示例:

std::shared_ptr<CContainer> other = std::move(spContainer);

这调用了一个移动操作,因为shared_ptr左边有一个移动构造函数,它接受另一个shared_ptr相同类型的参数作为参数。


推荐阅读