使用类成员的智能指针
我无法理解智能指针在C ++ 11中作为类成员的用法。 我读了很多关于智能指针的信息,我想我明白unique_ptr
和shared_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... }
假设我想用智能指针replace指针。 unique_ptr
不会因为getDevice()
而工作,对吗? 那么这是我使用shared_ptr
和weak_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... }
这是要走的路吗? 非常感谢!
unique_ptr
不会因为getDevice()
而工作,对吗?
不,不一定。 这里重要的是为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: 您可能想知道为什么我在这里使用原始指针,当大家一直说,原始指针是坏的,不安全的和危险的。 实际上,这是一个宝贵的警告,但重要的是将它放在正确的上下文中: 用于执行手动内存pipe理 (即通过new
和delete
分配和释放对象)的raw指针是不好的。 当用纯粹的方式来实现引用语义并传递非拥有的观察指针时,在原始指针中没有任何内在的危险,除了可能的原因是应该注意不要引用悬挂的指针。 – 完注1 ]
注2: 在注释中出现的情况下,在这种情况下,所有权是唯一的,拥有对象总是保证存在(即内部数据成员device
永远不会是nullptr
),函数getDevice()
可以(也许应该)返回一个引用,而不是一个指针。 虽然这是真的,但我决定在这里返回一个原始指针,因为我的意思是这是一个简短的答案,可以推广到device
可能为nullptr
,并且显示只要没有使用原始指针就可以他们进行手动内存pipe理。 – 完注2 ]
当然,情况是完全不同的,如果你的Settings
对象不应该拥有设备的独占所有权。 例如,如果Settings
对象的销毁不应该暗指销毁指向的Device
对象,则情况可能如此。
这是只有你作为你的程序devise师可以告诉; 从你提供的例子来看,我很难判断是否是这种情况。
为了帮助你解决这个问题,你可能会问自己,除了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
s,1为所有指针( shared_ptr
和weak_ptr
)。 当所有shared_ptr
被删除时,指针被删除。 当从weak_ptr
需要指针时,应该使用lock
来获取指针(如果存在的话)。