为什么使用"新"是个坏主意?
Why is it a bad idea to use 'new'?
可能重复:
在C++中,为什么要尽可能少地使用new
?
在C++中实例化类时使用"new"真的是个坏主意吗?在这里找到。
我知道使用原始指针是不明智的,但既然这是一种糟糕的做法,为什么还要使用"new"关键字呢?还是这样?
关键是new
与妊娠非常相似,它创建了一个手动管理的资源(即由您(,因此它具有责任。
C++是一种用于库编写的语言,每当你看到责任时,"C++"方法就是编写一个库元素来处理这个,而且只有这个责任。对于动态内存分配,这些库组件已经存在,概括地称为"智能指针";您将需要查看std::unique_ptr
和std::shared_ptr
(或它们的TR1或Boost等价物(。
在编写这些单一责任构建块时,您确实需要说new
和delete
。但您只需执行一次,然后仔细考虑并确保提供正确的复制、分配和销毁语义。(从异常安全的角度来看,单一责任至关重要,因为一次处理多个单一资源是非常不可扩展的。(
一旦你把所有的东西都考虑到合适的构建块中,你就将这些构建块组成越来越大的代码系统,但此时你就不需要再承担任何手动责任了,因为构建块已经为你做了这件事。
由于标准库为绝大多数用例(动态数组、智能指针、文件句柄、字符串(提供了资源管理类,因此关键是,一个精心设计的C++项目应该不需要任何类型的手动资源管理,其中包括new
的使用。所有的处理程序对象要么是自动的(作用域(,要么是其他类的成员,这些类的实例反过来又由某人作用域或管理。
考虑到这一点,您应该说new
的唯一时间是在创建新的资源管理对象时;尽管即便如此,这并不总是必要的:
std::unique_ptr<Foo> p1(new Foo(1, 'a', -2.5)); // unique pointer
std::shared_ptr<Foo> p2(new Foo(1, 'a', -2.5)); // shared pointer
auto p3 = std::make_shared<Foo>(1, 'a', -2.5); // equivalent to p2, but better
更新:我想我可能只解决了OP一半的担忧。许多来自其他语言的人似乎认为任何对象都必须用new
类型的表达式实例化。当使用C++时,这本身就是一种非常无益的心态:
C++中的关键区别是对象lifetime或"存储类"。这可以是以下其中之一:自动(作用域(、静态或动态。全局变量具有静态生存期。绝大多数变量(在本地范围内声明为Foo x;
(都具有自动生存期。只有对于动态存储,我们才使用new
表达式。当从另一种OO语言使用C++时,最重要的一点是,大多数对象只需要具有自动生存期,因此无需担心。
因此,第一个实现应该是"C++很少需要动态存储"。我觉得这可能是OP问题的一部分。这个问题最好用"动态分配对象真的是个坏主意吗?"来表达。只有在之后,您才决定真正需要动态存储,我们才能讨论您是否应该经常使用new
和delete
,或者是否有更好的替代方案,这就是我最初回答的要点。
尽可能避免new
意味着许多好处,例如:
-
首先,还要避免
delete
语句。尽管聪明的指针可以在这里帮助你。所以这不是重点。 -
您可以避免"三条规则"(在C++03中(或"五条规则"。如果在设计类时使用
new
,也就是说,当类在内部管理原始内存时,可能必须考虑此规则。 -
当您不使用
new
时,很容易实现异常安全代码。否则,您将面临大量问题,从而确保代码异常的安全性。
不必要地使用new
意味着你会引发问题。我看到,当一个没有经验的程序员使用new
时,他通常有更好的替代方案,比如使用标准容器和算法。使用标准容器避免了显式使用new
所带来的大多数问题。
这还不错,但用new
分配的所有内容都必须用delete
来处理。这样做并不总是微不足道的,尤其是当您考虑到异常情况时。我想这就是那个帖子的意思。
这不是一个"使用新东西的坏主意"——发帖者错误地陈述了他的情况。相反,使用新的和不给你两种不同的东西。
new
为您提供了一个新的、单独分配的类实例,并返回一个指向该实例的指针。
使用不带new
的类名会创建一个类的自动实例,当它超出作用域时,该实例将变为"poof"。这将"返回"实例本身,而不是指针(因此会返回其他线程中的语法错误(。
如果在引用的情况下使用new
并添加*
来传递编译器,则会导致对象泄漏。另一方面,如果您将一个参数传递给一个要将其存储在某个地方的方法,并且您传递了一个非新实例,使其与&
一起工作,那么您最终会存储一个悬空指针。
new
什么是delete
,free
什么是malloc
(不要把它们混合在一起,你会遇到麻烦的(。有时你必须使用new,因为用new分配的数据不会超出范围。。。除非数据指针丢失(这是new
的全部问题(。但这是程序员的错误,而不是关键词。
这取决于代码的需求。它是您引用的回复,向量包含客户端实例,而不是指向客户端实例的指针。
在C++中,您可以直接在堆栈上创建对象,而无需使用新的,如下面代码中的V1和V2:
void someFct()
{
std::vector<client> V1;
//....
std::vector<client*> V2;
}
使用V2时,您必须使用新操作创建新的客户端实例,但当V2超出范围时,客户端对象将不会被释放(删除(。没有垃圾收集器。在离开函数之前,必须删除对象。
要自动删除创建的实例,可以使用std::shared_ptr。这使得代码的编写时间更长,但从长远来看维护起来更简单:
void someFct()
{
typedef std::shared_ptr<client> client_ptr;
typedef std::vector<client_ptr> client_array;
client_array V2;
V2.push_back(client_ptr(new client()));
// The client instance are now automatically released when the function ends,
// even if an exception is thrown.
}
在C++中实例化类时使用"new"真的是个坏主意吗?
它通常很糟糕,因为它不是必要的,而且当你不恶意使用它时,代码会变得容易得多。如果你不使用它就可以逃脱惩罚,那就这样做吧。我已经在不使用new
的情况下编写了整个库。
我知道使用原始指针是不明智的,但既然这是一种糟糕的做法,为什么还要使用"new"关键字呢?还是这样?
这并不是普遍的糟糕,只是大多数时候没有必要。但也有合适的时候,这就是为什么会有这样一个关键词。也就是说,如果没有关键字,C++本可以逃脱惩罚,因为new
合并了两个概念:1。它分配内存,以及2。它将内存初始化为对象。
您可以通过使用其他内存分配方式,然后调用构造函数("placement-new"(来解耦这些进程。这实际上是通过分配器在所有地方完成的,比如标准库。
另一方面,客户端代码管理未初始化的内存很少有意义(读作:never(,因此不解耦这两个进程是有意义的。因此CCD_ 35的存在。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 为什么 std::unique 不调用 std::sort?
- 既然存在危险,为什么项目要使用-I include开关
- 为什么在运行时没有向我们提供有关分段错误的更多信息?