【问题标题】:Does default-initializing a non-const reference function parameter from a dynamically allocated dereferenced pointer create a memory leak?从动态分配的取消引用指针默认初始化非常量引用函数参数会造成内存泄漏吗?
【发布时间】:2016-10-28 15:12:11
【问题描述】:

我在前面,将不得不处理 C++98,可能是 C++03 和 C++11:

type1 myfunc( type2& var = /*some value of type "type2"*/ )
{
   // Some code
}

我试过了:

type1 myfunc( type2& var = *(new type2) )
{
   // Some code
}

当然它有效,但我不确定这是否会造成内存泄漏。这段代码在计算机内存中精确做什么? 如果我不能这样做,除了重载我的函数之外,我还有其他解决方案吗?

【问题讨论】:

  • 如果可以,请使用 const ref,这样您就可以临时使用。如果不能,请将全局变量作为默认参数。如果不能,请使用可选的 ref 作为输入。
  • 做一个超载,不要分配任何东西。见this。当然是漏水了。
  • 更多关于 const 引用 here
  • 是的。它会泄漏内存。
  • 也许右值引用会满足您的需求? type1 myfunc( type2&& var = type2() ) { /*... */ }

标签: c++ c++11 memory-leaks c++98


【解决方案1】:

问题被标记为C++11,所以我想你可以使用std::unique_ptr来解决这个问题。

一个小例子

#include <memory>
#include <iostream>

std::size_t myfunc( std::string const & var
   = * std::unique_ptr<std::string>(new std::string("default string")) )
{ return var.size(); }

int main ()
 {
   std::cout << "default:  " << myfunc() << std::endl;
   std::cout << "argument: " << myfunc("no default") << std::endl;

   return 0;
 }

希望这会有所帮助。

---新增C++98/C++03解决方案---

不清楚 OP 想要使用什么语言。

对于 C++98/C++03,可以使用 std::auto_ptr 代替 C++11 std::unique_ptr。

我记得 std::auto_ptr 已从 C++11 中弃用,因此仅在您不能使用 C++11(或更新的标准)时使用它

以下示例应符合 C++98(我也删除了 const)

#include <memory>
#include <iostream>

std::size_t myfunc(std::string & var
   = * std::auto_ptr<std::string>(new std::string("default string")) )
{ return var.size(); }

int main ()
 {
   std::string noDef("no default");

   std::cout << "default:  " << myfunc() << std::endl;
   std::cout << "argument: " << myfunc(noDef) << std::endl;

   return 0;
 }

【讨论】:

  • @BenjaminLindley - 你确定吗?
  • @NicolBolas:你确定?根据我的示例,这也适用于非常量引用(并不是说它是一个特别好的解决方案)
  • @max66:不,我的错。我忘记了初始化表达式发生在调用函数的上下文中。
  • @NicolBolas - 我尝试了一个类似于 MikeMB 的测试,即使没有 const,我的测试类的破坏也在函数的末尾。
  • 如果可以证明这是一个没有 const 的可靠解决方案,那将非常有趣。我很想知道标准对以这种方式声明的对象的生命周期有何规定。
【解决方案2】:

在使用默认参数的情况下,此代码会造成内存泄漏,除非myfunc 释放它(这将是一种黑客攻击):

type1 myfunc( type2& var = *(new type2) ) {
   // Some code
   delete &var; // Very bad, don't do it like that.
}

使用为var 指定的参数进行调用时,如果没有delete,就不会发生内存泄漏。这是因为编译器看到您正在为引用参数传递一个参数,而不是分配new type2。

在不造成内存泄漏的情况下创建默认引用的一种方法是定义一个静态一次性变量,并将其用作引用:

static type2 throwaway;
type1 myfunc( type2& var = throwaway ) {
    // Some code
}

这样,不需要查看对var 所做修改的调用者将能够调用您的函数而无需为其指定引用。当然,如果myfunc 对var 进行任何修改,调用者将无法看到它们。

【讨论】:

  • 如果第一个函数是用参数调用的,你会在一个不一定用new分配的对象上调用delete。
  • 恕我直言,你应该 - 至少 - 扔掉 thread_local 以避免隐藏的数据竞争。
  • @BenjaminLindley 没错,这正是我称之为 hack 并添加评论的原因。
【解决方案3】:

如果您分配内存但不删除它,则无论您使用取消引用、引用或指针操作进行何种恶作剧,都会发生内存泄漏。

【讨论】:

    猜你喜欢
    • 2018-08-13
    • 2015-04-17
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    相关资源
    最近更新 更多