为什么使用' new'?

时间:2011-10-01 13:05:41

标签: c++

  

可能重复:
  In C++, why should new be used as little as possible?

在C ++中实例化一个类时使用'new'真是个坏主意吗? Found here

我认为使用原始指针是不明智的,但为什么有一个'新'关键字,当它是如此糟糕的做法?或者是吗?

7 个答案:

答案 0 :(得分:16)

重点是new,就像怀孕一样,创建一个手动管理的资源(即),因此它带有责任

C ++是一种用于编写库的语言,每当你看到一个责任时,“C ++”方法就是编写一个库元素来处理这个,而且只有这个,责任。对于动态内存分配,这些库组件已经存在,并且概括地称为“智能指针”;你会想看std::unique_ptrstd::shared_ptr(或他们的TR1或Boost等价物)。

在编写这些单一责任构建块时,您确实需要说newdelete。但是你这样做一次,你仔细考虑它并确保你提供正确的拷贝,赋值和破坏语义。 (从异常安全的角度来看,单一责任是至关重要的,因为一次处理多个单一资源是非常不可扩展的。)

一旦将所有因素都考虑在合适的构建模块中,您就可以将这些模块组合成越来越大的代码系统,但此时您不再需要再承担任何手动责任了,因为积木已经为你做了这件事。

由于标准库为绝大多数用例(动态数组,智能指针,文件句柄,字符串)提供了资源管理类,因此重点在于一个经过精心设计和精心设计的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问题的一部分。问题可能更好地表达为“动态分配对象是一个非常糟糕的主意吗?”。只有 之后你决定你真的需要动态存储,我们才会讨论你是否应该经常说newdelete,或者是否有更好的选择,这是我最初的答案。

答案 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)

newdeletefree你的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