首页 > 解决方案 > std::shared_ptr 为空但不为空

问题描述

http://www.cplusplus.com/reference/memory/shared_ptr/

不拥有任何指针的 shared_ptr 称为空 shared_ptr。不指向任何对象的 shared_ptr 称为 null shared_ptr 并且不应被取消引用。请注意,空的 shared_ptr 不一定是空的 shared_ptr,空的 shared_ptr 也不一定是空的 shared_ptr。

我是否能够创建一个空的 std::shared_ptr,即一个不拥有任何东西但不为空的 std::shared_ptr,即包含有效负载?

用例是将“遗留”代码与现代指针结合起来:鉴于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,是否有不同的智能指针可用或根本没有?

标签: c++c++11visual-c++c++17smart-pointers

解决方案


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
}

然而,这会导致糟糕的设计。回到问题XY:目的是什么?有人可能会将对象作为原始指针传递给您(但可能会传递一个 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();
}

推荐阅读