2

我想知道是否可以通过创建私有/受保护的析构函数并同时使用 shared_ptrs 来确保自动资源管理(shared_ptr 的 RAII 特性)来强制在堆上创建对象。可以以不同的方式完成吗?我问这个的原因是因为我在 STL 听到的(还没有看到)没有虚拟析构函数,所以除了...shared_ptr 之外没有其他方法可以确保安全销毁?如果是这样,由于 shared_ptr 正在尝试访问析构函数,因此无法强制对象进入堆。无论如何绕过这些限制?

4

2 回答 2

4

C++ 是一种将代码的正确性交到程序员手中的语言。试图通过一些复杂的方法来改变它通常会导致代码难以使用或不能很好地工作。强迫程序员的手,以便(s)他必须在堆上创建一个对象,即使对于那种特定情况来说这不是“正确的”也是很糟糕的。如果他愿意,让程序员射他/她自己的脚。

在较大的项目中,代码应由同行(最好至少有时由更高级的人员)审查,以确保其正确性并遵循项目的编码指南。

我不完全确定“虚拟析构函数”与“安全销毁”和“共享指针”之间的关系——这三个不同的概念并不密切相关——当一个类用作基类时需要虚拟析构函数派生一个新的类。STL 对象并不意味着派生自[通常,您使用模板或继承,尽管它们可以组合,但当您这样做时它会很快变得非常复杂],因此无需在 STL 中使用虚拟析构函数。

如果您有一个作为基类的类,并且存储是基于对基类的指针或引用完成的,那么您必须具有虚拟析构函数 - 或者不要使用继承。

我认为“安全销毁”是指“没有内存泄漏”[而不是“正确销毁”,这当然也可能是一个问题-并导致内存泄漏问题]。对于大量情况,这意味着“首先不要使用指向对象的指针”。我在 SO 上看到很多例子,程序员new完全没有理由打电话。vector<X>* v = new vector<X>;绝对是“难闻的气味”(就像鱼或肉一样,如果气味难闻,则代码有问题)。如果您正在调用 new,那么使用共享指针、唯一指针或其他一些“包装”是个好主意。但是你不应该强迫这个概念 - 偶尔有很好的理由不这样做。

“共享指针”是“对象不再使用时自动销毁”的概念,是避免内存泄漏的有用技术。

既然我已经告诉你不要这样做,这是实现它的一种方法:

class X
{
    private:
       int x; 
       X() : x(42) {}; 
    public:
       static shared_ptr<X> makeX() { return make_shared<X>(); }
};

由于构造函数是私有的,类的“用户”不能调用“new”或创建这种对象。[您可能还希望将复制构造函数和赋值运算符放在私有或使用delete以防止它们被使用]。

但是,我仍然认为首先这是一个坏主意。

于 2013-08-03T13:56:34.043 回答
1

Mats的回答确实是错误的。make_shared需要一个公共构造函数。但是,以下内容是有效的:

class X
{
private:
    int x;

    X() : x( 42 ) {};
public:

    static std::shared_ptr<X> makeX()
    {
        return std::shared_ptr<X>( new X() );
    }
};

我不喜欢使用new关键字,但在这种情况下,这是唯一的方法。

于 2019-06-06T08:29:10.297 回答