繁体   English   中英

为类成员使用智能指针

[英]Using smart pointers for class members

我无法理解智能指针在C ++ 11中作为类成员的用法。 我已经阅读了很多关于智能指针的内容,我想我确实理解unique_ptrshared_ptr / weak_ptr工作原理。 我不明白的是真正的用法。 似乎每个人都建议使用unique_ptr作为几乎所有时间的方式。 但是,我将如何实现这样的事情:

class Device {
};

class Settings {
    Device *device;
public:
    Settings(Device *device) {
        this->device = device;
    }

    Device *getDevice() {
        return device;
    }
};    

int main() {
    Device *device = new Device();
    Settings settings(device);
    // ...
    Device *myDevice = settings.getDevice();
    // do something with myDevice...
}

假设我想用智能指针替换指针。 由于getDevice()unique_ptr不起作用,对吧? 那是我使用shared_ptrweak_ptr 没办法使用unique_ptr 在大多数情况下,似乎我觉得shared_ptr更有意义,除非我在一个非常小的范围内使用指针?

class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(std::shared_ptr<Device> device) {
        this->device = device;
    }

    std::weak_ptr<Device> getDevice() {
        return device;
    }
};

int main() {
    std::shared_ptr<Device> device(new Device());
    Settings settings(device);
    // ...
    std::weak_ptr<Device> myDevice = settings.getDevice();
    // do something with myDevice...
}

这是要走的路吗? 非常感谢!

由于getDevice()unique_ptr不起作用,对吧?

不,不一定。 这里重要的是为您的Device对象确定适当的所有权策略 ,即谁将成为您的(智能)指针指向的对象的所有者。

它会单独作为Settings对象的实例吗? Settings对象被销毁时,是否必须自动销毁Device对象,还是它应该比该对象更长?

在第一种情况下, std::unique_ptr是您所需要的,因为它使得Settings成为指向对象的唯一(唯一)所有者,并且是唯一负责其销毁的对象。

在这个假设下, getDevice()应该返回一个简单的观察指针(观察指针是不保持指向对象存活的指针)。 最简单的观察指针是原始指针:

#include <memory>

class Device {
};

class Settings {
    std::unique_ptr<Device> device;
public:
    Settings(std::unique_ptr<Device> d) {
        device = std::move(d);
    }

    Device* getDevice() {
        return device.get();
    }
};

int main() {
    std::unique_ptr<Device> device(new Device());
    Settings settings(std::move(device));
    // ...
    Device *myDevice = settings.getDevice();
    // do something with myDevice...
}

[ 注1: 你可能想知道为什么我在这里使用原始指针,当每个人都在告诉原始指针是坏的,不安全的和危险的。 实际上,这是一个宝贵的警告,但重要的是将它置于正确的上下文中:原始指针在用于执行手动内存管理时是不好的,即通过newdelete分配和释放对象。 当纯粹用作实现引用语义和传递非拥有,观察指针的手段时,原始指针中没有任何本质上的危险,除了可能因为人们应该注意不要取消引用悬空指针。 - 结束注1 ]

[ 注2: 正如评论中出现的那样,在这种特殊情况下,所有权是唯一的, 并且始终保证所拥有的对象存在(即内部数据成员device永远不会是nullptr ),函数getDevice()可以(也许应该)返回引用而不是指针。 虽然这是真的,我决定在这里返回一个原始指针,因为我的意思是一个简短的答案,可以推广到device可能是nullptr ,并显示原始指针是正常的,只要一个不使用它们用于手动内存管理。 - 结束注2 ]


当然,如果您的Settings对象具有设备的独占所有权,则情况完全不同。 例如,如果Settings对象的销毁不应该暗示销毁指向的Device对象,则可能就是这种情况。

这是只有你作为你的程序设计师才能分辨出来的东西; 从您提供的示例中,我很难判断是否是这种情况。

为了帮助您弄清楚,您可能会问自己除了Settings之外是否有任何其他对象有权保持Device对象保持活动状态,只要它们持有指向它的指针,而不仅仅是被动观察者。 如果确实如此,那么您需要一个共享所有权策略 ,这是std::shared_ptr提供的:

#include <memory>

class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(std::shared_ptr<Device> const& d) {
        device = d;
    }

    std::shared_ptr<Device> getDevice() {
        return device;
    }
};

int main() {
    std::shared_ptr<Device> device = std::make_shared<Device>();
    Settings settings(device);
    // ...
    std::shared_ptr<Device> myDevice = settings.getDevice();
    // do something with myDevice...
}

请注意, weak_ptr是一个观察指针,而不是一个拥有指针 - 换句话说,如果指向对象的所有其他拥有指针超出范围,它不会使指向的对象保持活动状态。

weak_ptr优于常规原始指针的优点是,您可以安全地判断weak_ptr是否悬空 (即它是指向有效对象,还是最初指向的对象已被破坏)。 这可以通过调用weak_ptr对象上的expired()成员函数来完成。

class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(const std::shared_ptr<Device>& device) : device(device) {

    }

    const std::shared_ptr<Device>& getDevice() {
        return device;
    }
};

int main()
{
    std::shared_ptr<Device> device(new Device());
    Settings settings(device);
    // ...
    std::shared_ptr<Device> myDevice(settings.getDevice());
    // do something with myDevice...
    return 0;
}

week_ptr仅用于参考循环。 依赖图必须是非循环定向图。 在共享指针中有2个引用计数:1表示shared_ptr ,1表示所有指针( shared_ptrweak_ptr )。 删除所有shared_ptr后,将删除指针。 weak_ptr需要指针时,应该使用lock来获取指针(如果存在)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM