答案 0 :(得分:16)
重点是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 ++中的关键区别在于对象生命周期或“存储类”。这可以是以下之一:自动(范围),静态(永久)或动态(手动)。全局变量具有静态生存期。绝大多数变量(在本地范围内声明为Foo x;
)具有自动生命周期。只有动态存储才能使用new
表达式。从另一种OO语言转向C ++时,最重要的事情是大多数对象只需要具有自动生命周期,因此无需担心任何事情。
所以第一个实现应该是“C ++很少需要动态存储”。我觉得这可能是OP问题的一部分。问题可能更好地表达为“动态分配对象是一个非常糟糕的主意吗?”。只有在 之后你决定你真的需要动态存储,我们才会讨论你是否应该经常说new
和delete
,或者是否有更好的选择,这是我最初的答案。
答案 1 :(得分:3)
尽可能避免new
意味着许多好处,例如:
首先,您还要避免delete
语句。虽然智能指针可以帮助您。所以这不是那么重要。
你可以避免三条规则(在C ++ 03中)或五条规则(在C ++ 11中)。如果在设计类时使用new
,也就是说,当您的类在内部管理原始内存时,可能必须考虑此规则。
不使用new
时,很容易实现异常安全的代码。否则,你将面临很多问题,使你的代码异常安全。
不必要地使用new
意味着您正在邀请问题。我见过一个没有经验的程序员使用new
时,他经常有更好的选择,比如使用标准容器和算法。使用标准容器避免了明确使用new
时出现的大多数问题。
答案 2 :(得分:2)
这不错,但是您使用new
分配的所有内容都必须使用delete
取消分配。这并不总是微不足道,特别是当你考虑到异常时。
我认为这就是那篇文章的意思。
答案 3 :(得分:0)
这不是一个“使用新的坏主意” - 海报错误地反驳了他的情况。相反,使用新的而不是给你两个不同的东西。
new
为您提供一个新的,单独分配的类实例,并返回指向该实例的指针。
使用不带new
的类名创建了一个类的自动实例,当它超出范围时将变为“poof”。这“返回”实例本身,而不是指针(因此在其他线程中出现语法错误)。
如果在引用的情况下使用new
并添加*
来传递编译器,则会导致泄漏的对象。另一方面,如果您将参数传递给将要存储在某个地方的方法,并且您传递了一个非新实例,使其与&
一起使用,那么您最终会晃来晃去指针存储。
答案 4 :(得分:0)
new
你delete
和free
你的malloc
(不要混合它们,你会遇到麻烦)。有时您必须使用new,因为使用new分配的数据不会超出范围...除非数据指针丢失,这是new
的整个问题。
但这在程序员方面是错误的,而不是关键字。
答案 5 :(得分:0)
这取决于代码需要什么。它是你引用的回复,向量包含客户端实例,而不是指向客户端实例的指针。
在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.
}
答案 6 :(得分:0)
在C ++中实例化一个类时使用'new'真是个坏主意吗?
这通常很糟糕,因为它没有必要,并且当你不虚假地使用它时代码变得更容易。如果您可以在不使用它的情况下离开,请执行此操作。我没有使用new
编写完整的库。
我认为使用原始指针是不明智的,但为什么有一个'新'关键字,当它是如此糟糕的做法?或者是吗?
它不是普遍坏,大多数时候都是不必要的。但也有时候它是合适的,这就是为什么有这样一个关键字。也就是说,C ++ 可以在没有关键字的情况下离开,因为new
会混淆两个概念:1。分配内存,2。初始化对象的内存。
您可以使用其他内存分配方法来解耦这些进程,然后是构造函数调用(“placement new”)。这实际上是通过分配器在整个地方完成的,例如标准库。
另一方面,很少(读取:从不)对客户端代码管理未初始化的内存很有意义,因此不分离这两个进程是有意义的。因此存在new
。