C++构造函数中分配内存的正确方式是什么?

7

在C++构造函数中,通过new分配内存的正确方法是哪种。第一种方法是在参数列表中:

class Boda {
    int *memory;
    public:
        Boda(int length) : memory(new int [length]) {}
        ~Boda() { delete [] memory; }
};

或在构造函数的主体中:

class Boda {
    int *memory;
    public:
        Boda(int length) {
            memory = new int [length];
        }
        ~Boda() { delete [] memory; }
};

感谢您,Boda Cydo。

6
我知道这只是示例代码,但按照现有的写法,该类存在严重的内存管理问题(默认复制构造函数会允许多次释放内存)。使用RAII,使用智能指针或容器。通过适当的RAII,您可能会发现根本不需要自己使用delete。 - jk.
8
@jk:同意,我更喜欢使用std::vector<int> - fredoverflow
6个回答

3
我认为最简单的方法是使用boost作用域数组,让其他经过充分测试的库代码为您处理所有内容。因此:
class Boda {
    boost::scoped_array<int> memory;
    public:
        Boda(int length) : memory(new int [length]) {}
       ~Boda() {}
};

此外,范围数组是不能被复制的-因此,您可以避免另一个答案中提到的令人讨厌的复制构造函数释放问题。

实际上,你应该使用boost::scoped_array - Pedro d'Aquino
谢谢。刚注意到它是一个数组分配。教我认真阅读问题。 - Alex Wilson
1
“delete” 是一种代码异味:它应该只出现在专门的资源管理类中……而这些类通常已经在可用的库(例如 STL / Boost)中正确编码了。 - Matthieu M.

2

请阅读或搜索常见问题解答(FAQ),获取有关编程的相关信息。这是一个链接+1,以便访问FAQ。 - Thomas Matthews

2

你应该使用资源管理类来为你处理这一部分。否则,除了需要不必要地复制现有逻辑和维护复制/赋值运算符之外,你还会遇到一些严重的异常安全问题。


如果我需要像这个例子中那样快速地管理已分配的数组怎么办? 我的项目中有完全相同的类(还有一些其他方法),并且我被禁止使用任何库。对于这个特定的实例,我需要(也想)自己管理内存。 - Adam Bajger

1

我认为两者在产生的效果上是等价的,都是“正确的方式”。 我更喜欢初始化列表,但我会选择第二种变体,只是为了能够在尝试分配内存之前测试无效的长度参数。


1
它们对于简单类型是等价的,但一般情况下并非如此。使用初始化列表将从参数构造对象;而使用构造函数体将会默认构造该对象,然后重新赋值。这可能不是很高效,并且仅在对象可被默认构造和赋值的情况下才有效。 - Mike Seymour

0

memory成员变量是一个指针,如果你在初始化列表中分配它的内存失败了,那么你的类就没有被初始化,你不需要后续释放它(感谢RAII设计模式,C++用于类初始化)。如果你在构造函数体内分配其内存,则会发生类似的行为。

但是,如果你想要处理一些事情,那么就在构造函数体内分配其内存。检查一些东西或尝试/捕获它或打印一些有用的消息,但至少,你必须抛出另一个异常,因为你的类初始化已经破坏了。

我认为,在构造函数体内分配memory的内存比另一种方法更易读。


-1
如果你想捕获内存分配错误(这很可能是必须的),那么你就必须在构造函数的主体中调用 new。

12
实际上不是这样的。在这两种情况下,如果内存分配失败,这个构造函数无能为力,因此不应该捕获异常。而且您可以使用函数尝试块将整个内容放在try-catch块中。 - GManNickG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接