关于new和delete的使用,以及Stroustrup的建议......
他说的话(但不完全是,这来自我的书中的笔记):
根据经验,
new
属于构造函数和类似操作,delete
属于析构函数。此外,new
通常用于资源句柄的参数。否则,请避免使用new
和delete
,而是使用资源句柄(智能指针)。
我想知道更有经验的C ++ 11用户是否真的应用了这个。
我对此的印象是,哇这似乎是一个非常酷的规则。 但是,就任何一般规则而言,我都怀疑。在一天结束时 你将最终使用new并在必要时删除。但也许这个规则 是一个很好的指导方针,我不知道。
答案 0 :(得分:48)
这是一个很好的规则。实际上,您可以通过使用适当的new
函数来避免在智能指针的参数中使用make_
。例如,而不是:
std::shared_ptr<int> p(new int(5));
您经常可以这样做:
auto p = std::make_shared<int>(5);
这也有更多例外安全的好处。虽然std::make_unique
尚不存在,但计划进入C ++ 14(它已经在工作草案中)。如果您现在需要,可以使用existing implementations。
您可以更进一步,甚至避免在构造函数和析构函数中使用new
和delete
。如果你总是在智能指针中包装动态分配的对象,即使它们是类成员,你根本不需要管理你自己的内存。请参阅Rule of Zero。这个想法是,你的类不负责实现任何形式的所有权语义(SRP) - 这就是智能指针的用途。那么理论上你永远不必编写复制/移动构造函数,复制/移动赋值运算符或析构函数,因为隐式定义的函数通常会做适当的事情。
答案 1 :(得分:14)
似乎更像是一个民意调查而不是一个问题,但在这里它是:在应用程序代码中我通常根本不使用new
。由于我们的编码指南,代码确实使用指针,但这些“裸”指针中没有一个实际上是转移所有权。所有对象都归其他对象所有。
公平地说,当需要分配对象时,分配通常使用的东西在道德上等同于std::make_shared<T>(...)
,有时会在应用程序代码中显示。这种相当彻底缺少new
(或类似)的一个主要原因是对象通常使用有状态分配器进行分配,而不是通过资源管理器实际上恰好相当复杂。因此,在应用程序代码中使用new
或其放置版本进行直接内存分配的地方很少。
在某些基础架构代码中,特别是在创建自定义容器时,情况略有不同:在那里分配了内存(来自分配器并使用放置new
初始化)。但是,即使存在内存分配和对象初始化的任何结果,也会立即传递给资源管理器。基本上,我无法应对明确的资源管理,使用资源管理员只是让我放心了必要的工作。
答案 2 :(得分:3)
我想到的方式是每个资源都应归某些东西所有。业主是负责清理的人。通常这个拥有者是某种智能指针,但即使是std :: vector也是一个资源所有者:存储它的连续元素的内存块。这个建议不仅适用于内存,还适用于任何资源,如文件描述符,数据库句柄,互斥体等......
当您在代码的某些部分中手动调用new并手动删除时,程序员将成为资源所有者。拥有所有权后,您需要自行清理。现在,您和所有追随您的维护程序员必须确保新的所有代码路径最终导致删除。即使是简单的功能,这也很容易出错。除非您仔细地将所有内容包装在try catch块中,否则几乎不可能,除非您将所有内容包装在运行程序性能中,否则会使用额外的范围和不必要的异常逻最后,即使你做得对,你也浪费了很多时间来完成这项乏味的资源管理工作。编译器是可以为您完成此工作的工具,使用它。
最糟糕的情况是,当某个子系统分配资源时,它会在应用程序周围传递,而其他一些远程子系统会释放它。在这种情况下可能的代码路径的数量是难以处理的。如果不是不可能的话,人类很难推理和信任。在我看来,这种编程风格是不可维护的。您过去使用了多少个C项目,这些项目充满了内存错误,尤其是在很少从未执行错误处理路径的情况下?我已经处理了比我更关心的事情了。
C有手动内存管理,Java等有垃圾回收。 C ++有RAII。它和C一样有效,并且几乎和垃圾收集一样安全。
我的规则很简单,如果您发现自己手动清理了任何资源,那么您刚刚写了一个错误。