对类成员使用智能指针
Using smart pointers for class members
我在理解 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...
}
假设我想用智能指针替换指针。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
对象的实例?当Device
对象被销毁时,Settings
对象是否必须自动销毁,还是应该比该对象存活?
在第一种情况下,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:你可能想知道为什么我在这里使用原始指针,因为每个人都在说原始指针是不好的,不安全的和危险的。实际上,这是一个宝贵的警告,但重要的是要将其放在正确的上下文中:原始指针在用于执行手动内存管理(即通过new
和delete
分配和解除分配对象(时是不好的。当纯粹用作实现引用语义和传递非拥有、观察指针的手段时,原始指针中没有任何本质上的危险,除了应该注意不要取消引用悬空指针的事实。- 尾注1]
[注2:正如注释中出现的那样,在这种特殊情况下,所有权是唯一的并且拥有的对象始终保证存在(即内部数据成员device
永远不会nullptr
(,函数getDevice()
可以(也许应该(返回引用而不是指针。虽然这是真的,但我决定在这里返回一个原始指针,因为我的意思是一个简短的答案,可以推广到可以nullptr
device
的情况,并表明只要不将它们用于手动内存管理,原始指针就可以了。- 尾注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
s,1 表示所有指针(shared_ptr
和 weak_ptr
(。删除所有shared_ptr
时,指针将被删除。当需要来自weak_ptr
的指针时,应该使用lock
来获取指针(如果存在(。
- 1d 智能指针不适用于语法 (*)++
- 优先顺序:智能指针和类析构函数
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 智能指针作为无序映射键,并通过引用进行比较
- 智能指针概念所有权和寿命
- 正在理解智能指针,但出现错误:未分配正在释放的指针
- 尝试使用智能指针时引发异常
- 我可以制作指向智能指针的智能指针吗?
- 通过智能指针和转换对基本模板参数进行模板推导
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 从堆栈分配的原始指针构造智能指针
- 初始化指向类实例的智能指针并访问其方法
- 如何使用 std::make_shared 创建基类类型的智能指针?
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 编译器不会使用 -std=c++11 编译智能指针
- 具有智能指针的多态性
- C++:矢量分配器行为、内存分配和智能指针
- 在什么情况下,需要共享智能指针而无法使用唯一指针?
- 指向函数签名中的常量智能指针
- 使用智能指针附加的继承对象的深层复制