c++ - 防止多个 shared_ptr 指向同一个对象的最佳方法

标签 c++ c++11 shared-ptr

将相同的指针发送到两个不同的 shared_ptr 是不好的,它会导致双重释放,如下所示:

int* p = new int;
std::shared_ptr<int> p1(p);
std::shared_ptr<int> p2(p); // BAD

您可以使用 std::enable_shared_from_this 实现相同的目的:

class Good: public std::enable_shared_from_this<Good>
{
public:
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

int main()
{
    std::shared_ptr<Good> gp1(new Good);
    std::shared_ptr<Good> gp2 = gp1->getptr();
}

但这仍然不能防止:

class Good: public std::enable_shared_from_this<Good>
{
public:
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

int main()
{
    Good* p = new Good;
    std::shared_ptr<Good> gp3(p);
    std::shared_ptr<Good> gp4(p); // BAD
}

如果你有这样的代码,这可能会成为一个问题:

void Function(std::shared_ptr<Good> p)
{
    std::cout << p.use_count() << '\n';
}

int main()
{
    Good* p = new Good;
    std::shared_ptr<Good> p1(p);
    Function(p);    // BAD
}

既然有智能指针,为什么还要使用普通指针?因为在性能关键代码中(或为了方便)shared_ptr 或 weak_ptr 的开销是不可取的。

为了防止这个错误,我做了:

class CResource : public shared_ptr<Good>
{
public:
    CResource()
    {
    }

    CResource(std::shared_ptr<CBaseControl> c)
        : CResource(c)
    {
    }

private:
    CResource(CBaseControl* p)
    {
    }
};

void Function(CResource p)
{
    std::cout << p.use_count() << '\n';
}

int main()
{
    Good* p = new Good;
    CResource p1(std::shared_ptr<Good>(p));
    Function(p);    // Error
}

如果有人试图用指针而不是 shared_ptr 调用 Function,这将导致编译器出错。虽然它不会阻止某人声明 void Function(std::shared_ptr p),但我认为这不太可能。

这还很糟糕吗?有更好的方法吗?

最佳答案

解决方案很简单:从一开始就不要让原始指针拥有自己的内存。这种模式:

int* p = new int;
std::shared_ptr<int> p1(p);
std::shared_ptr<int> p2(p); // BAD

根本不应该存在。从您的代码库中消除它。 new 在 C++11 中唯一合法的地方是作为对智能指针的构造函数调用的参数(或者在非常低水平的东西)。

即有这样的代码:

std::shared_ptr<int> p1(new int);

或者更好(不再涉及裸new):

auto p1 = std::make_shared<int>();

请注意,在代码中使用原始指针没有问题(但在我见过的大多数 C++ 代码中,我什至会质疑这一点)。但是如果你使用原始指针,不要让它们拥有内存。指向自动存储(无需资源管理)或使用 unique_ptr 并通过其 get 成员函数访问原始指针。

关于c++ - 防止多个 shared_ptr 指向同一个对象的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11223895/

相关文章:

c++ - 需要帮助在 C++ 中进行多线程

c++ - 基本移动分配运算符的调用顺序

c++ - 来自 Boost.Atomic 示例的无等待队列崩溃

c++ - 了解当传递给函数时,shared_ptr 引用计数何时增加

c++ - shared_ptr 在我可以正确使用它之前就被销毁了

c++ - 我什么时候应该更喜欢 `shared_ptr` 而不是 `make_shared` ?

c++ - round 函数返回错误的双重估计

c++ - 为什么用 debug_rep(&s) 调用模板 <typename T> string debug_rep(T *p) 时 T 不是 string*

c++ - 如何将基于迭代器的 for 循环重写为基于范围的循环 (C++11)

c++ - 简单的嵌套类