为什么创建STL容器动态地被认为是不好的做法?

And*_*rey 7 c++ stl

标题说.

糟糕的样本:

std::vector<Point>* FindPoints()
{
   std::vector<Point>* result = new std::vector<Point>();
   //...
   return result;
}
Run Code Online (Sandbox Code Playgroud)

如果我vector稍后删除它会有什么问题?

我主要用C#编程,所以在C++上下文中这个问题对我来说并不是很清楚.

Mat*_*lia 11

根据经验,您不这样做,因为您在堆上分配的越少,泄漏内存的风险就越小. :)

std::vector也很有用,因为它以RAII方式自动管理用于矢量的内存; 现在,通过在堆上分配它,您需要显式释放(with delete result)以避免泄漏其内存.由于例外情况,事情变得复杂,这可能会改变您的返回路径并跳过delete您放置的任何路径.(在C#中,您没有这样的问题,因为垃圾收集器会定期调用无法访问的内存)

如果要返回STL容器,可以选择以下几种:

  • 按价值归还; 从理论上讲,由于在返回过程中产生的临时性,你应该招致复制 - result但是较新的编译器应该能够使用NRVO 1删除副本.可能还有std::vector像许多std::string实现一样实现写时复制优化的实现,但我从未听说过.

    相反,在C++ 0x编译器上,移动语义应该触发,避免任何副本.

  • 将结果指针存储在所有权转移智能指针中std::auto_ptr(或std::unique_ptr在C++ 0x中),并将函数的返回类型更改为std::auto_ptr<std::vector<Point > >; 以这种方式,你的指针总是封装在一个堆栈对象中,当函数退出时(以任何方式)自动销毁,并销毁vector它仍由它拥有的if.此外,完全清楚谁拥有返回的对象.
  • 使result向量成为调用者通过引用传递的参数,并填充该向量而不是返回新向量.
  • Hardcore STL选项:您可以将数据作为迭代器提供; 然后,客户端代码将使用std::copy+ std::back_inserter或其他任何内容将这些数据存储在它想要的任何容器中.看不多(代码正确可能很棘手),但值得一提.

  1. 正如@Steve Jessop在评论中指出的那样,只有在返回值直接用于初始化调用方法中的变量时,NRVO才能完全工作; 否则,它仍然可以忽略临时返回值的构造,但是仍然可以调用为其分配返回值的变量的赋值运算符(有关详细信息,请参阅@Steve Jessop的注释).

  • @John:我知道你不应该使用`std :: auto_ptr`作为STL容器的*elements*,但我不明白为什么你不应该使用它们来管理在堆上分配的STL容器的生命周期. (2认同)
  • "较新的编译器应该能够使用NRVO来删除副本" - 仅当结果用于初始化变量时.如果它被分配给以前存在的变量,那么复制构造函数elision可以摆脱临时,但仍然有一个无法省略的赋值.C++ 0x移动语义也解决了这种情况(通过使分配变得便宜).因此,使用C++ 0x,没有太多理由避免按值返回标准容器,但是使用C++ 03时,存在涉及完整副本的尴尬案例. (2认同)

Jer*_*fin 6

除非真的有必要,否则动态创建任何东西都是不好的做法.动态创建容器的理由很少,因此通常不是一个好主意.

编辑:通常,大多数代码只应处理容器中的迭代器(或两个),而不是担心返回容器的速度有多快.