在构造函数初始化列表中分配内存是否有任何问题? 我在C++程序中使用了大量的初始化列表,但是没有意识到你可以在它们里面分配内存。

在构造函数初始化列表中分配内存是否有任何问题? 我在C++程序中使用了大量的初始化列表,但是没有意识到你可以在它们里面分配内存。,c++,C++,因此,您可以这样做(作为一个人为的例子): class Test { private: int* i; int* j; int count; int* k; public: Test(void) : i(new int), j(new int[10]), count(10), k(new int[count]) { } ~Test(void) { delete i; delete [] j

因此,您可以这样做(作为一个人为的例子):

class Test
{
private:
    int* i;
    int* j;
    int count;
    int* k;

public:
    Test(void) : i(new int), j(new int[10]), count(10), k(new int[count])
    {
    }

    ~Test(void)
    {
        delete i;
        delete [] j;
        delete [] k;
    }
};

以这种方式进行内存分配有什么问题吗?关于这里的初始化顺序,由同一列表中的一个参数初始化是否安全?i、 e.当我在使用前分配
计数时,使用它是否安全,或者是否有一些特殊的初始化顺序我可能会遇到冲突?

它不是异常安全的。如果
j
new
抛出异常,则不会调用
Test
的析构函数,因此不会释放
i
的内存

如果
j
的初始值设定项抛出,则调用
i
的析构函数,只是原始指针没有析构函数。因此,您可以使用合适的智能指针替换
i
,以确保异常安全。在这种情况下,
i
unique\u ptr
j
unique\u ptr
就可以了


您可以依靠初始值设定项以正确的顺序执行(定义成员的顺序,不一定是列表中的顺序)。它们可以安全地使用已经初始化的数据成员,因此在
k

的初始值设定项中使用
count
没有问题。如果初始值设定项引发异常,则此代码可能会泄漏内存


请注意,如果
Test
的成员是智能指针,而不是原始指针,则可以使其正常工作。

初始化没有问题——它们由标准保证按顺序完成,但是,请记住,如果这些分配中的任何一个失败,前一个分配将不会被释放

因此,唯一的缺点是,如果您希望对失败的分配保持安全,那么您更希望将它们初始化为
nil
,并在构造函数中将分配包装在
try
块中。但这通常是不需要的,除非您的应用程序面临内存不足的真正危险,并且需要从中恢复


当然,假设只有内存不足才能引发异常,这是正确的——如果您分配了可以引发其他异常的对象,您应该更担心它。

从初始值设定项列表调用
new
没有具体问题

但是,如果您对多个成员执行此操作,它将不会是异常安全的,并且有泄漏内存的风险(如果第一个
new
调用成功,但第二个调用抛出异常,那么第一个分配将泄漏)

至于依赖初始化顺序,这是完全安全的。成员按照类声明中列出的顺序进行初始化。因此,您可以使用提前初始化的成员的值来初始化“稍后”的成员

请记住,决定初始化顺序的是它们在类中的声明顺序,而不是它们在初始化列表中的顺序。:)

假设您有:

class Foo
{
public:
    T* p1;
    T* p2;

    Foo()
    : p1(new T),
      p2(new T)
    {
    }
};

如果初始化
p2
失败(因为
new
抛出内存不足异常或
T
构造函数失败),则
p1
将泄漏。与此相抗衡,C++允许在初始化列表中使用<代码>尝试<代码> >代码> catch >代码,但通常都很粗略。

您正在将内存分配到初始化列表中;这是完全正确的,但是您将把内存中的指针分配给原始指针

这些原始指针并不意味着它们所指向的指针的任何类型的内存所有权或删除,因此,代码包含多个内存泄漏,不遵循“五条规则”,并且通常是不好的

编写
测试
的更好方法是:

class Test
{
private:
    //Assuming you actually want dynamic memory allocation:
    std::unique_ptr<int> i;
    std::unique_ptr<int[]> j;
    int count;
    std::unique_ptr<int[]> k;

public:
    Test(void) : i(new int), j(new int[10]), count(10), k(new int[count])
    {
    }
};
类测试
{
私人:
//假设您确实需要动态内存分配:
std::唯一的ptr i;
std::唯一的_ptr j;
整数计数;
std::唯一的_ptrk;
公众:
测试(无效):i(新整数),j(新整数[10]),计数(10),k(新整数[count])
{
}
};

史蒂夫·杰索普的回答存在陷阱

关于订单,我想这就是你的问题:

12.6.2/4

初始化应按以下顺序进行:

[……]

  • 然后,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(同样,无论顺序如何) mem初始值设定项的名称)

因为在您的类中,
count
是在
k
之前声明的,所以您没问题。

请注意,初始化顺序不是由ctor初始值设定项决定的,而是由变量的声明顺序决定的。另请注意,正确的答案可能取决于您是否希望代码在出现新抛出时是异常安全的。因此,特别是,如果类在初始值设定项列表中多次调用
new
,则这是一个问题。:)@Firedragon-不,因为在创建时无法保证成员变量为零,所以无法判断哪些变量已经初始化。@Firedragon:使异常安全的最简单方法是使用智能指针,而不是原始指针;这也意味着您不需要编写类中缺少的析构函数、复制构造函数和复制赋值运算符。添加异常处理程序是相当难看的,而且有点容易出错。@SteveJessop也许。您仍然有构造函数体来强制类不变量,如果不满足这些不变量,则清理并抛出它们。@MikeSeymour智能指针是一种解决方案。我见过的另一个用法是将所有指针下推到私有基类中,其构造函数将它们初始化为
NULL
,who