std::shared_ptr 为空但不为空
std::shared_ptr which is empty but not null
http://www.cplusplus.com/reference/memory/shared_ptr/ 说
A shared_ptr that does not own any pointer is called an empty shared_ptr. A shared_ptr that points to no object is called a null shared_ptr and shall not be dereferenced. Notice though that an empty shared_ptr is not necessarily a null shared_ptr, and a null shared_ptr is not necessarily an empty shared_ptr.
我可以创建一个空的 std::shared_ptr,即不拥有任何东西但不为空,即包含有效负载吗?
用例是将 "legacy" 代码与现代指针结合起来:鉴于 foo
的调用语法不会更改,
void foo(const MyClass* p) {
if (p == nullptr) {
auto defaultObject = std::make_shared<MyClass>("some", "parameters");
defaultObject->doSomething();
...
defaultObject->doSomethingElse();
// The default object must be destroyed again
} else {
p->doSomething();
...
p->doSomethingElse();
// p must not be destroyed, its memory is managed somewhere else
}
}
是否有 doNotOwnButStillPointTo()
的实现允许这样做:
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = doNotOwnButStillPointTo(p);
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
或者,为了不爱上 XY-Problem,是否有不同的智能指针可用或 none?
- 不过,我想补充一点,
std::make_shared<MyClass>("some", "parameters")
行实际上是对创建 shared_ptr 的更复杂函数的调用。我想保留这个功能并使用它的结果
shared_ptr
有一个删除器。这是一个破坏底层对象的多态过程。您可能有一个空的删除器:
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = std::shared_ptr<MyClass>(p, [](MyClass*){});
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
但这会导致糟糕的设计。回到 ProblemXY:目的是什么?有人可能会向您传递一个对象作为原始指针(但可能会传递一个 nullptr)。如果提供的是 nullptr 而不是真实对象,您希望创建一个本地对象。您可能希望防止内存泄漏。好的
void foo(const MyClass* p) {
std::shared_ptr<MyClass> local;
if (p == nullptr) {
// Create a default object
local = std::make_shared<MyClass>("some", "parameters");
p = local.get();
}
// p is always valid, local will always be destroyed (if exists)
p->doSomething();
...
p->doSomethingElse();
}
您正在寻找的是 shared_ptr
的自定义删除器构造器。这是为了允许共享指针接管来自其他地方的指针,当它被销毁时,它将 运行 您的自定义代码而不是调用 delete。在这种情况下,您的自定义代码将什么都不做,因为您不想删除指针。那看起来像
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = std::shared_ptr(p, [](auto){ });
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
Am I able to create an empty std::shared_ptr, i.e. one which does not own anything but which is not null, i.e. contains payload?
确实可以。链接页面的说法是正确的 empty shared_ptr is not necessary a null shared_ptr.
可以使用构造函数创建这样的共享指针
template< class Y >
shared_ptr(const shared_ptr<Y>&, element_type*);
如果你传递一个空的空共享指针作为第一个参数,非空指针作为第二个参数,那么你将得到一个空的非空共享指针。
构造函数通常用于指向拥有对象的成员或别名,但它恰好也匹配这种极端情况。特别注意不要让这个共享指针泄漏到这个函数的范围之外。
你的情况:
wrapper = {std::shared_ptr<void>{}, p};
Or, to not fall for the XY-Problem, is there a different smart pointer available or none at all?
另一种方法是仅将共享指针用于默认对象的所有权,并通过 p
调用函数:
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
p = wrapper.get();
}
p->doSomething();
...
p->doSomethingElse();
站点 cplusplus.com 对语言的使用往往没有那么严格,尤其是相对于标准而言。它更喜欢本地语言,因此可能会造成混淆。
这尤其与 smart_ptr
到 "own" 的含义有关。 From the standard:
A shared_ptr
is said to be empty if it does not own a pointer.
这与shared_ptr
对"ownership"的想法有关。从 shared_ptr
的角度来看,它 "owns" 是一个指针,如果它是用一个指针值创建的,它将在其上调用删除函子(给定或默认)。任何不以这种方式 "own" 指针的 shared_ptr
都是空的。
然而,这与人类的想法截然不同 "ownership"。人们可能会说,如果您向 shared_ptr
提供删除器,但实际上并没有 删除 对象或以其他方式释放它,那么 shared_ptr
不会t 真的拥有指针。
但就 shared_ptr
(及其各种接口)而言,它拥有该指针,即使您给定的删除器不会对它做任何事情。
至于如何处理你的代码特定代码,最好使用unique_ptr
并有条件地给它一个销毁的值:
void foo(const MyClass* p) {
unique_ptr<MyClass> u_p;
if (p == nullptr) {
u_p = std::make_unique<MyClass>("some", "parameters");
p = u_p.get();
}
p->doSomething();
...
p->doSomethingElse();
// p must not be destroyed, its memory is managed somewhere else
}
http://www.cplusplus.com/reference/memory/shared_ptr/ 说
A shared_ptr that does not own any pointer is called an empty shared_ptr. A shared_ptr that points to no object is called a null shared_ptr and shall not be dereferenced. Notice though that an empty shared_ptr is not necessarily a null shared_ptr, and a null shared_ptr is not necessarily an empty shared_ptr.
我可以创建一个空的 std::shared_ptr,即不拥有任何东西但不为空,即包含有效负载吗?
用例是将 "legacy" 代码与现代指针结合起来:鉴于 foo
的调用语法不会更改,
void foo(const MyClass* p) {
if (p == nullptr) {
auto defaultObject = std::make_shared<MyClass>("some", "parameters");
defaultObject->doSomething();
...
defaultObject->doSomethingElse();
// The default object must be destroyed again
} else {
p->doSomething();
...
p->doSomethingElse();
// p must not be destroyed, its memory is managed somewhere else
}
}
是否有 doNotOwnButStillPointTo()
的实现允许这样做:
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = doNotOwnButStillPointTo(p);
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
或者,为了不爱上 XY-Problem,是否有不同的智能指针可用或 none?
- 不过,我想补充一点,
std::make_shared<MyClass>("some", "parameters")
行实际上是对创建 shared_ptr 的更复杂函数的调用。我想保留这个功能并使用它的结果
shared_ptr
有一个删除器。这是一个破坏底层对象的多态过程。您可能有一个空的删除器:
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = std::shared_ptr<MyClass>(p, [](MyClass*){});
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
但这会导致糟糕的设计。回到 ProblemXY:目的是什么?有人可能会向您传递一个对象作为原始指针(但可能会传递一个 nullptr)。如果提供的是 nullptr 而不是真实对象,您希望创建一个本地对象。您可能希望防止内存泄漏。好的
void foo(const MyClass* p) {
std::shared_ptr<MyClass> local;
if (p == nullptr) {
// Create a default object
local = std::make_shared<MyClass>("some", "parameters");
p = local.get();
}
// p is always valid, local will always be destroyed (if exists)
p->doSomething();
...
p->doSomethingElse();
}
您正在寻找的是 shared_ptr
的自定义删除器构造器。这是为了允许共享指针接管来自其他地方的指针,当它被销毁时,它将 运行 您的自定义代码而不是调用 delete。在这种情况下,您的自定义代码将什么都不做,因为您不想删除指针。那看起来像
void foo(const MyClass* p) {
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
} else {
wrapper = std::shared_ptr(p, [](auto){ });
}
wrapper->doSomething();
...
wrapper->doSomethingElse();
// p mus not be destroyed, the default object (if created) shall be
}
Am I able to create an empty std::shared_ptr, i.e. one which does not own anything but which is not null, i.e. contains payload?
确实可以。链接页面的说法是正确的 empty shared_ptr is not necessary a null shared_ptr.
可以使用构造函数创建这样的共享指针
template< class Y >
shared_ptr(const shared_ptr<Y>&, element_type*);
如果你传递一个空的空共享指针作为第一个参数,非空指针作为第二个参数,那么你将得到一个空的非空共享指针。
构造函数通常用于指向拥有对象的成员或别名,但它恰好也匹配这种极端情况。特别注意不要让这个共享指针泄漏到这个函数的范围之外。
你的情况:
wrapper = {std::shared_ptr<void>{}, p};
Or, to not fall for the XY-Problem, is there a different smart pointer available or none at all?
另一种方法是仅将共享指针用于默认对象的所有权,并通过 p
调用函数:
std::shared_ptr<MyClass> wrapper;
if (p == nullptr) {
// Create a default object
wrapper = std::make_shared<MyClass>("some", "parameters");
p = wrapper.get();
}
p->doSomething();
...
p->doSomethingElse();
站点 cplusplus.com 对语言的使用往往没有那么严格,尤其是相对于标准而言。它更喜欢本地语言,因此可能会造成混淆。
这尤其与 smart_ptr
到 "own" 的含义有关。 From the standard:
A
shared_ptr
is said to be empty if it does not own a pointer.
这与shared_ptr
对"ownership"的想法有关。从 shared_ptr
的角度来看,它 "owns" 是一个指针,如果它是用一个指针值创建的,它将在其上调用删除函子(给定或默认)。任何不以这种方式 "own" 指针的 shared_ptr
都是空的。
然而,这与人类的想法截然不同 "ownership"。人们可能会说,如果您向 shared_ptr
提供删除器,但实际上并没有 删除 对象或以其他方式释放它,那么 shared_ptr
不会t 真的拥有指针。
但就 shared_ptr
(及其各种接口)而言,它拥有该指针,即使您给定的删除器不会对它做任何事情。
至于如何处理你的代码特定代码,最好使用unique_ptr
并有条件地给它一个销毁的值:
void foo(const MyClass* p) {
unique_ptr<MyClass> u_p;
if (p == nullptr) {
u_p = std::make_unique<MyClass>("some", "parameters");
p = u_p.get();
}
p->doSomething();
...
p->doSomethingElse();
// p must not be destroyed, its memory is managed somewhere else
}