默认参数中的 c++ new 运算符及其副作用

Posted

技术标签:

【中文标题】默认参数中的 c++ new 运算符及其副作用【英文标题】:The c++ new operator in default arguments and its side-effects 【发布时间】:2018-03-17 13:04:44 【问题描述】:

我对 c++ 中的默认参数有疑问。如果我有这样的功能:

int foo(int* obj = new Int(4)) 
    /* Stuff with obj. */

当然,这里整数只是作为示例,但问题是我是否要为这样的参数提供一个值:

int x = 2;
foo(&x);

即使我为参数提供了一个值并因此分配了我无法再读取的内存,是否仍会评估表达式 obj = new Int(4)

【问题讨论】:

只有在没有参数的情况下调用函数时才会评估默认参数。 否,那么new 将不会被执行。但要注意,如果没有传递任何参数,如果你没有delete 指针,你可能会发生内存泄漏。如果你对指针执行delete,你怎么能区分传递给非新分配对象的指针和分配新对象的指针之间的区别? (提示:你不能!)简而言之,使用new 作为默认参数是一个非常个坏主意! 【参考方案1】:

使用new 表达式作为参数的默认值,如

 int foo(int *obj = new int(4));

这是一个非常糟糕的主意,因为可能存在一些行为不一致的用例,并且可能出现许多糟糕的结果。

假设,为了便于讨论,foo() 的实现是这样的

 delete obj;

如果调用者做任何一个都可以

 foo();             //  default argument is a new expression
 foo(new int(2));

但如果调用者执行以下一项或多项操作,则会导致未定义的行为;

 foo(&some_int);      //  some_int is a variable local to the caller
 foo(new int[2]);     //   dynamically allocates an array

相反,假设foo() 不执行delete obj。在这种情况下,这些语句中的任何一个

 foo();
 foo(new int(3));
 foo(new int [2]);      // dynamically allocates an array

导致内存泄漏,并且

  foo(&some_int);

可能会正常工作(假设foo() 不会以其他方式调用未定义的行为)。

真正的问题是foo() 无法(在标准 C++ 的范围内)检测调用者执行上述哪个操作。因此,存在未定义行为或内存泄漏的真正风险,除非调用者确实做了“正确的事情”(其中“正确的事情”意味着不会导致内存泄漏或未定义的行为)。而且,由于有更多的选择可以做错事,调用者很可能不会做完全正确的事。请记住,程序员在阅读文档方面是出了名的糟糕,因此依靠文档来确保调用者(或在调用者中编写代码的程序员)执行避免上述问题所需的操作是一种糟糕的方法。

【讨论】:

即使我在默认参数中不使用new,我仍然无法检查调用者传递的对象是否在堆上分配,因此调用者必须处理内存并相应地删除对象,对吗?这将是有问题的,因为创建了对象的层次结构,并且调用者要么需要实现删除每个孩子的算法,要么以某种方式保留对孩子的引用。这两种“解决方案”都需要大量代码,这些代码也必须重复。有没有办法在编译时检查对象是如何分配的? 在C++的范围内,没有。【参考方案2】:

不,默认参数仅在没有参数传递给它们时使用。 new 不会被调用,因此不会有内存分配。此外,正如一些程序员老兄所说,如果您在函数体内部(或外部)的某个时间点不清理,就会出现内存泄漏。

【讨论】:

以上是关于默认参数中的 c++ new 运算符及其副作用的主要内容,如果未能解决你的问题,请参考以下文章

ES6—带默认值的函数参数及其作用域

C++之重载运算与类型转换

C++ 类和对象

C++ 类和对象

c++基础篇——类与对象入门(中)

c++基础_ new, delete概述及其使用!!