在构造函数初始化列表中分配内存是否存在任何问题
Are there any issues with allocating memory within constructor initialization lists?
我在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;
delete [] k;
}
};
用这种方式分配内存有什么问题吗?关于这里的初始化顺序,由同一列表中的一个初始化参数来初始化参数是否安全?即,当我在使用之前分配count
时,使用它是否安全,或者是否存在我可能会违反的某些特殊初始化顺序?
它不是异常安全的。如果j
的new
抛出异常,则不会调用Test
的析构函数,因此不会释放i
的内存。
如果j
的初始值设定项抛出,就会调用i
的析构函数,这只是原始指针没有析构函数。因此,您可以通过用合适的智能指针替换i
来确保异常安全。在这种情况下,i
的unique_ptr<int>
和j
的unique_ptr<int[]>
就可以了
您可以依赖初始值设定项以其正确的顺序执行(成员的定义顺序,而不一定是列表中的顺序)。它们可以安全地使用已经初始化的数据成员,因此在k
的初始化器中使用count
没有问题。
当初始化程序抛出异常时,此代码可能会泄漏内存。
请注意,如果Test
的成员是智能指针而不是原始指针,则可以使其正常工作。
从初始值设定项列表中调用new
没有特定问题。
然而,如果您为多个成员执行此操作,则不会出现异常安全,并且有泄漏内存的风险(如果第一个new
调用成功,但第二个调用抛出异常怎么办?那么第一个分配就会泄漏)。
至于依赖初始化顺序,这是完全安全的。成员按照它们在类声明中列出的顺序进行初始化。因此,您可以使用早期初始化的成员的值来初始化"稍后"的成员。
请记住,决定初始化顺序的是它们在类中的声明顺序,而不是它们在初始化列表中的顺序。:)
您正在初始化程序列表中分配内存;这是完全可以的,但是您要将指向该内存的指针分配给原始指针。
这些原始指针并不意味着它们所指向的指针有任何内存所有权或删除,因此,代码包含多个内存泄漏,不遵循"五条规则",而且通常很糟糕。
编写Test
的更好方法是:
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])
{
}
};
初始化没有问题——标准保证它们按顺序进行,但请记住,如果这些分配中的任何一个失败,前一个分配都不会被释放。
因此,唯一的缺点是,如果您想防止分配失败,那么您更希望将它们初始化为nil
,并在构造函数中将分配封装在try
块中。不过,通常不需要这样做,除非您的应用程序面临内存不足的真正危险,并且需要从中恢复。
当然,假设只有内存不足才能引发异常,这也是正确的——如果你分配了可以引发其他异常的对象,你应该更担心它
假设您有:
class Foo
{
public:
T* p1;
T* p2;
Foo()
: p1(new T),
p2(new T)
{
}
};
如果初始化p2
失败(因为new
抛出内存不足异常,或者因为T
构造函数失败),则p1
将被泄漏。为了解决这个问题,C++允许在初始化列表中使用try
/catch
,但这通常很粗糙
Steve Jessop的回答存在陷阱。
关于订单,我认为这就是你的问题所解决的:
12.6.2/4
初始化应按以下顺序进行:
[…]
- 然后,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(同样,无论顺序如何mem初始化器的)
因为在您的类中,count
是在k
之前声明的,所以您可以。
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 如何检查QList中是否存在值
- 根据某个函数是否存在启用模板
- 地图计数确实很重要,或者只是检查是否存在
- C++中是否存在 std::conditional 的懒惰等价物?
- 无论如何,我可以确定构造函数是否存在吗?
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- 堆分配的对象是否存在永不为空的唯一所有者?
- 扩展类中的可选 vir 函数,测试它在运行时是否存在
- 模板化检查是否存在带有参数列表的类成员函数?
- 是否存在包含负号的isdigit函数(过载)
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 检查编译时是否存在静态函数
- 向量是否存在行主要形式?
- 检查 TinyXML 中的元素是否存在
- 检测是否存在具有 C++17 的类成员
- 虚拟继承中是否存在多重继承?
- 我遇到了这个代码片段,不明白. 它递归检查 C++ 字符串中是否存在大写字符
- std::weak_ptr 和相应的 std::shared_ptr 之间是否存在数据竞争?
- 是否存在用于 C 或 C++ 中常见数学运算(例如最小值、最大值和平均值)的可导入库?