为什么我不能用删除或私有析构函数分配类的数组?

时间:2017-06-27 06:32:49

标签: c++ heap destructor private

我最近遇到了这个问题。我正在使用的库使用引用计数对象并实现自己的处理方式。部分实现是库的每个类都有一个私有析构函数。我猜测这是为了防止在库自动管理对象生存期时在堆栈上创建对象(它是一个场景图)。

无论如何,我想在堆上分配这样一个类的数组并遇到以下问题:

#include <iostream>

using namespace std;

    class test
    {
    public:
        test() {
            cout << "ctor" << endl;
        }

        //~test() = delete; also doesnt work

    private:
        ~test()
        {
            cout << "dtor" << endl;
        }

    };

    int main()
    {
        //works
        auto oneInstance = new test;

        //doesnt work
        auto manyInstances = new test[3];
    }

使用GCC进行数组分配会产生以下错误:

source_file.cpp: In function ‘int main()’:
source_file.cpp:15:5: error: ‘test::~test()’ is private
     ~test()
     ^
source_file.cpp:26:36: error: within this context
     auto manyInstances = new test[3];
                                    ^

为了在堆上分配这个类的数组,为什么析构函数需要公共/可用?当只分配像之前一行中的单个实例时,它工作正常。我也尝试使用更现代的“删除”语法,但它产生了相同的结果。

新的[]运算符中是否有任何我不知道的魔法?

编辑:

感谢您的快速帮助。我想知道为什么这段代码不会两次打印“dtor”:

#include <iostream>

using namespace std;

class test
{
public:
    test() {
        static int allocations = 0;
        ++allocations;

        if(allocations == 3)
        {
            //produce exception
            throw 1;
        }
        cout << "ctor" << endl;
    }

    ~test()
    {
        cout << "dtor" << endl;
    }

};

int main()
{
    //works
    auto oneInstance = new test;

    //doesnt work
    try {
    auto manyInstances = new test[3];
    }
    catch(...)
    {
            cout << "error?";
    }
}

打印:

ctor ctor dtor error?

1 个答案:

答案 0 :(得分:13)

由于例外情况,new[]的数组版本必须在异常传播时调用先前已分配的元素上的析构函数,以确保异常安全。单个元素new不需要这样做。如果分配失败,它就会失败,不需要销毁任何东西。

§8.3.4新[expr.new/20]

  

如果new-expression创建了类类型的对象数组,则可能会调用析构函数

关于编辑,请参阅C ++ 17标准中的以下引用

§8.17抛出异常[expr.throw / 4]

  

如果当前没有处理异常,则评估没有操作数调用的throw-expression std::terminate()

关于您的第二次修改,您错过了通过test(而不是new)创建的new[]实例的计数,这导致test的第一个实例正在被创造,这就是建筑数量的混乱来自何处。