我目前正在努力理解
unique_ptr
的目的。
我希望在其他地方对存储在
std::unique_ptr<Component> component
类的任何实例中的 Object
内容进行某种引用。由于我们使用智能指针,原始指针pComp
永远不应该管理内存本身,因为unique_ptr
是唯一负责它的,这是智能指针的核心原则之一。然而,令我困惑的是,一旦我们超出范围并调用 unique_ptr
的析构函数(这反过来会释放内存),我就无法检查内存在代码的其他部分是否仍然有效引用但不拥有相同的内存地址(在本例中为 pComp
)。unique_ptr
是一个非常明确的声明,说明 Object
是该内存的所有者,其他人不应对它负责,但是如果我的其余代码无法检查内存是否仍然有效?unique_ptr
不将其内部指针设置为nullptr
?我是否误解了unique_ptr
的用法?有正确的方法吗?如果在这种情况下我应该使用 shared_ptr
,为什么要这样呢,因为我希望 Object 是唯一负责的呢?预先感谢大家。
#include <iostream>
#include <memory>
class Component
{
public:
Component() { std::cout << "Component Constructor" << std::endl; }
~Component() { std::cout << "Component Destructor" << std::endl; }
};
class Object
{
public:
std::unique_ptr<Component> component;
Object() : component(std::make_unique<Component>()) { std::cout << "Object Constructor" << std::endl; }
~Object() { std::cout << "Object Destructor" << std::endl; }
};
int main()
{
Component* pComp = nullptr;
{
Object obj;
pComp = obj.component.get();
}
if (pComp == nullptr)
std::cout << "pComp is nullptr\n"; // This code is never reached.
return 0;
}
编辑:好的,我看到了
pComp
的问题。我意识到我误解了一个基本概念。即使 unique_ptr
将其内部指针设置为 nullptr
,也不会自动将 pComp
设置为 nullptr
,因此 pComp
只会成为悬空指针,因为它指向的内存已被释放。感谢大家帮助我理解这一点。
尽管如此,我对
unique_ptr
的使用仍然感到困惑。如果我可以在其他地方检查nullptr
的参考资料的唯一方法是:
class Component
{
public:
Component() { std::cout << "Component Constructor" << std::endl; }
~Component() { std::cout << "Component Destructor" << std::endl; }
};
class Object
{
public:
std::shared_ptr<Component> component; // This is now shared_ptr
Object() : component(std::make_shared<Component>()) { std::cout << "Object Constructor" << std::endl; }
~Object() { std::cout << "Object Destructor" << std::endl; }
};
int main()
{
std::weak_ptr<Component> pComp{}; // weak_ptr istead of raw pointer
{
Object obj;
pComp = obj.component;
}
if (pComp.expired())
std::cout << "pComp is expired\n";
return 0;
}
在独特所有权方面,
unique_ptr
有什么用处?虽然之前的解决方案有效,因为从技术上讲,内存的唯一“真正所有者”是 obj
,但该解决方案是不明确的。 shared_ptr
允许程序员复制它并在其他地方创建一个shared_ptr
,这意味着我们现在在其他地方有另一个所有者,这不是我想要的。我什至无法通过强制使用 weak_ptr
来阻止这种情况。我是不是还误会了什么?如果 unique_ptr
意味着唯一的所有权,但我无法读取代码的其他部分(只能读取,不能拥有),因为我无法检查 nullptr
,那么我应该如何使用它呢?我应该只在Object
本身的范围内使用它而不是在它之外吗?
在您的示例中,
pComp
具有由obj.component
存储的指针值的副本。当
obj
被破坏时,该指针值的副本将变得无效。 C++ 中没有办法测试无效指针,程序员需要确保它们永远不会被访问。
为什么 unique_ptr 不将其内部指针设置为 nullptr?
unique_ptr
不会在其析构函数中将其底层指针清空,因为该指针即将不复存在。
有正确的方法吗?
不,您应该延长
obj
的生命周期,或者用您自己的 obj.component
获得 unique_ptr
的所有权。只有当您无法做到其中任何一个时,您才应该考虑更改为 shared_ptr
。
所以使用
unique_ptr
而不是指针。然后你会得到:
int main()
{
std::unique_ptr<Component> pComp;
{
Object obj;
pComp = obj.component; // compile error
}
}
如果您想要
std::move
组件脱离对象,或者您必须使用对象组件,这取决于您。
那么如果我的其余代码无法检查内存是否仍然有效,那么使用它还有什么意义呢?
RAII 风格自动内存释放。
为什么 unique_ptr 不将其内部指针设置为 nullptr?
为什么会这样?这是一个必须执行的指令,那就是时间。
有正确的方法吗?
这取决于 you you 定义对象的“正确”语义。 C++就是锤子,看你敲到哪里。
我应该在哪里使用shared_ptr,为什么要这样,因为我希望Object是唯一负责的?
听起来好像不行,我想你也想将 unique_ptr 设置为常量,这样你就无法移出它。
class Object
{
public:
const std::unique_ptr<Component> component;
...
{
Object obj;
pComp = std::move(obj.component); // also compile error
}
唯一的方法是使用
obj.component
来访问组件。但是,您仍然可以使用.get()
并获取原始指针。由程序员编写正确的代码。