简体   繁体   English

C++中的new运算符和java中的new运算符的区别

[英]Difference between new operator in C++ and new operator in java

As far as I know, the new operator does the following things: (please correct me if I am wrong.)据我所知, new运营商做了以下几件事:(如果我错了,请纠正我。)

  1. Allocates memory, and then returns the reference of the first block of the allocated memory.分配内存,然后返回分配内存的第一个块的引用。 (The memory is allocated from heap, obviously.) (显然,内存是从堆分配的。)
  2. Initialize the object (calling constructor.)初始化对象(调用构造函数。)

Also the operator new[] works in similar fashion except it does this for each and every element in the array.运算符new[]以类似的方式工作,只是它对数组中的每个元素都这样做。

Can anybody tell me how both of these operators and different in C++ and Java:谁能告诉我这两个运算符在 C++ 和 Java 中有何不同:

  1. In terms of their life cycle.就他们的生命周期而言。
  2. What if they fail to allocate memory.如果他们无法分配内存怎么办。
  • In C++, T * p = new T;在 C++ 中, T * p = new T; ... ...
  1. allocates enough memory for an object of type T ,T类型的对象分配足够的内存,

  2. constructs an object of type T in that memory, possibly initializing it, and在该内存中构造一个类型为T的对象,可能会对其进行初始化,并且

  3. returns a pointer to the object.返回一个指向对象的指针。 (The pointer has the same value as the address of the allocated memory for the standard new , but this needn't be the case for the array form new[] .) (该指针的值与为标准new分配的内存地址相同,但对于数组形式new[]不必如此。)

In case the memory allocation fails, an exception of type std::bad_alloc is thrown, no object is constructed and no memory is allocated.如果内存分配失败,则抛出std::bad_alloc类型的异常,不构造对象,也不分配内存。

In case the object constructor throws an exception, no object is (obviously) constructed, the memory is automatically released immediately, and the exception is propagated.如果对象构造函数抛出异常,则(显然)没有对象被构造,内存会立即自动释放,并传播异常。

Otherwise a dynamically allocated object has been constructed, and the user must manually destroy the object and release the memory, typically by saying delete p;否则,一个动态分配的对象已经被构造,用户必须手动销毁该对象并释放内存,通常是说delete p; . .

The actual allocation and deallocation function can be controlled in C++.实际的分配和释放功能可以在 C++ 中控制。 If there is nothing else, a global, predefined function ::operator new() is used, but this may be replaced by the user;如果没有别的,一个全局的、预定义的函数::operator new()被使用,但这可能被用户替换 and if there exists a static member function T::operator new , that one will be used instead.如果存在静态成员函数T::operator new ,则将使用该静态成员函数。

  • In Java it's fairly similar, only that the return value of new is something that can bind to a Java variable of type T (or a base thereof, such as Object ), and you must always have an initializer (so you'd say T x = new T(); ).在 Java 中,它非常相似,只是new的返回值是可以绑定到T类型的 Java 变量(或其基类,例如Object )的东西,并且您必须始终有一个初始化程序(因此您可以说T x = new T(); )。 The object's lifetime is indeterminate, but guaranteed to be at least as long as any variables still refer to the object, and there is no way to (nor any need to) destroy the object manually.对象的生命周期是不确定的,但保证至少与任何变量仍然引用对象一样长,并且没有办法(也不需要)手动销毁对象。 Java has no explicit notion of memory, and you cannot control the interna of the allocation. Java 没有明确的内存概念,您无法控制分配的内部。

Furthermore, C++ allows lots of different forms of new expressions (so-called placement forms).此外,C++ 允许许多不同形式的new表达式(所谓的放置形式)。 They all create dynamic-storage objects which must be destroyed manually, but they can be fairly arbitrary.它们都创建必须手动销毁的动态存储对象,但它们可以相当随意。 To my knowledge Java has no such facilities.据我所知,Java 没有这样的设施。


The biggest difference is probably in use : In Java, you use new all the time for everything, and you have to, since it's the one and only way to create (class-type) objects.最大的区别可能在于使用:在 Java 中,您始终对所有内容使用new ,而且您必须这样做,因为它是创建(类类型)对象的唯一方法。 By contrast, in C++ you should almost never have naked new s in user code.相比之下,在 C++ 中,您几乎不应该在用户代码中使用裸new C++ has unconstrained variables, and so variables themselves can be objects, and that is how objects are usually used in C++. C++ 有不受约束的变量,因此变量本身可以是对象,这就是 C++ 中通常使用对象的方式。

In your "statement", I don't think "returns a reference to the first block of allocated memory is quite right. new returns a pointer (to the type of the object allocated). This is subtly different from a reference, although conceptually similar.在你的“声明”中,我不认为“返回对分配内存的第一个块的引用是非常正确的new返回一个指针(指向分配的对象的类型)。这与引用有微妙的不同,尽管在概念上相似的。

Answers to your questions:回答您的问题:

  1. In C++ an object stays around in memory (see note) until it is explicitly deleted with delete or delete [] (and you must use the one matching what you allocated with, so a new int[1]; , although it is the same amount of memory as new int; can not be deleted with delete (and vice versa, delete [] can't be used for a new int ). In Java, the memory gets freed by the garbage collector at some point in the future once there is "no reference to the memory".在 C++ 中,对象保留在内存中(请参阅注释),直到使用deletedelete []显式删除它(并且您必须使用与分配的内容匹配的对象,因此new int[1]; ,尽管它是相同的内存量作为new int;不能用delete (反之亦然, delete []不能用于new int )。在 Java 中,垃圾收集器在将来的某个时刻释放内存一次没有“对内存的引用”。
  2. Both throw an exception (C++ throws std::bad_alloc , Java something like OutOfMemoryError), but in C++ you can use new(std::nothrow) ... , in which case new returns NULL if there isn't enough memory available to satisfy the call.两者都抛出异常(C++ 抛出std::bad_alloc ,Java 类似 OutOfMemoryError 的东西),但在 C++ 中你可以使用new(std::nothrow) ... ,在这种情况下,如果没有足够的可用内存, new返回 NULL满足呼唤。

Note: It is, as per comment, technically possible to "destroy" the object without freeing it's memory.注意:根据评论,技术上可以“销毁”对象而不释放它的内存。 This is a rather unusual case, and not something you should do unless you are REALLY experienced with C++ and you have a VERY good reason to do so.这是一个相当不寻常的情况,除非您真的有 C++ 经验并且有充分的理由这样做,否则您不应该这样做。 The typical use-case for this is inside the delete operator corresponding to a placement new (where new is called with an already existing memory address to just perform the construction of the object(s)).典型的用例是在与放置 new 相对应的 delete 运算符内部(其中new使用已经存在的内存地址调用以仅执行对象的构造)。 Again, placement new is pretty much special use of new, and not something you can expect to see much of in normal C++ code.同样,placement new 是new 的非常特殊的用法,而不是您可以期望在普通C++ 代码中看到的很多东西。

I don't know about details in Java, but here is what new and new[] do in C++:我不知道 Java 中的细节,但这里是newnew[]在 C++ 中的作用:

  1. Allocate memory分配内存

    When you have an expression new T or new T(args) , the compiler determines which function to call for getting memory当您有一个表达式new Tnew T(args) ,编译器会确定调用哪个函数来获取内存

    • If the type T has an appropriate member operator new that one is called如果类型T有一个适当的成员operator new ,则调用该成员
    • Otherwise, if the user provided an appropriate global operator new that one is called.否则,如果用户提供了适当的全局operator new ,则调用该operator new

      If operator new cannot allocate the requested memory, then it calls a new handler function, which you can set with set_new_handler .如果operator new无法分配请求的内存,则它会调用一个新的处理程序函数,您可以使用set_new_handler设置该set_new_handler That function may free some space so the allocation can succeed, it may terminate the program, or it may throw an exception of type std::bad_alloc or derived from that.该函数可能会释放一些空间以便分配可以成功,它可能会终止程序,或者它可能会抛出std::bad_alloc类型的异常或从中派生的异常。 The default new handler just throws std::bad_alloc .默认的新处理程序只是抛出std::bad_alloc

      The same happens for new T[n] except that operator new[] is called for memory allocation.除了调用operator new[]进行内存分配外, new T[n] operator new[]也会发生同样的情况。

  2. Construct the object resp.构造对象。 objects in the newly allocated memory.新分配的内存中的对象。

    For new T(args) the corresponding constructor of the object is called.对于new T(args)调用对象的相应构造函数。 If the constructor throws an exception, the memory is deallocated by calling the corresponding operator delete (which can be found in the same places as operator new )如果构造函数抛出异常,则通过调用相应的operator delete来释放内存(可以在与operator new相同的地方找到)

    For new T it depends if T is POD (ie a built-in type or basically a C struct/union) or not.对于new T它取决于T是否是 POD(即内置类型或基本上是 C 结构/联合)。 If T is POD, nothing happens, otherwise it is treated like new T() .如果 T 是 POD,则什么都不会发生,否则将被视为new T()

    For new T[n] it also depends on whether T is POD .对于new T[n]还取决于T是否为POD Again, PODs are not initialized.同样,POD 未初始化。 For non-PODs the default constructor is in turn called for each of the objects in order.对于非 POD,依次为每个对象依次调用默认构造函数。 If one object's default constructor throws, no further constructors are called, but the already constructed objects (which doesn't include the one whose constructor just threw) are destructed (ie have the destructor called) in reverse order.如果一个对象的默认构造函数抛出异常,则不会再调用其他构造函数,但已构造的对象(不包括其构造函数刚刚抛出的对象)以相反的顺序被销毁(即调用析构函数)。 Then the memory is deallocated with the appropriate operator delete[] .然后使用适当的operator delete[]释放内存。

  3. Returns a pointer to the newly created object(s).返回指向新创建对象的指针。 Note that for new[] the pointer will likely not point to the beginning of the allocated memory because there will likely be some information about the number of allocated objects preceding the constructed objects, which is used by delete[] to figure out how many objects to destruct.请注意,对于new[] ,指针可能不会指向已分配内存的开头,因为在构造对象之前可能会有一些有关已分配对象数量的信息, delete[]来确定有多少对象破坏。

In all cases, the objects live until they are destroyed with delete ptr (for objects allocated with normal new ) or delete[] ptr (for objects created with array new T[n] ).在所有情况下,对象一直存在,直到它们被delete ptr (对于使用普通new分配的对象)或delete[] ptr (对于使用数组new T[n]创建的对象)销毁。 Unless added with a third-party library, there's no garbage collection in C++.除非添加第三方库,否则 C++ 中没有垃圾收集。

Note that you also can call operator new and operator delete directly to allocate raw memory.请注意,您也可以直接调用operator newoperator delete来分配原始内存。 The same is true for operator new[] and operator delete[] . operator new[]operator delete[]也是如此。 However note that even for those low-level functions you may not mix the calls, eg by deallocating memory with operator delete that you allocated with operator new[] .但是请注意,即使对于那些低级函数,您也不能混合调用,例如,通过使用operator new[]分配的operator delete释放内存。

You can also copnstruct an object in allocated memory (no matter how you got that) with the so-called placement new.您还可以使用所谓的新放置在分配的内存中构建一个对象(无论您是如何获得的)。 This is done by giving the pointer to the raw memory as argument to new , like this: new(pMem) T(args) .这是通过将指向原始内存的指针作为参数提供给new ,如下所示: new(pMem) T(args) To destruct such an explicitly constructed object, you can call the object's destructor directly, p->~T() .要析构这样一个显式构造的对象,您可以直接调用对象的析构函数p->~T()

Placement new works by calling an operator new which takes the pointer as additional argument and just returns it.放置 new 的工作原理是调用一个operator new ,该operator new将指针作为附加参数并返回它。 This same mechanism can also be used to provide other information to operator new overloads which take corresponding additional arguments.同样的机制也可用于向采用相应附加参数的operator new重载提供其他信息。 However while you can define corresponding operator delete , those are only used for cleaning up when an object throws an exception during construction.但是,虽然您可以定义相应的operator delete ,但它们仅用于在对象在构造过程中抛出异常时进行清理。 There's no "placement delete" syntax.没有“放置删除”语法。

One other use of the placement new syntax which is already provided by C++ is nothrow new. C++ 已经提供的placement new 语法的另一种用法是nothrow new。 That one takes an additional parameter std::nothrow and differs from normal new only in that it returns a null pointer if allocation fails.那个接受一个额外的参数std::nothrow并且与普通的new不同之处仅在于它在分配失败时返回一个空指针。

Also note that new is not the only memory management mechanism in C++.另请注意, new并不是 C++ 中唯一的内存管理机制。 On the one hand, there are the C functions malloc and free .一方面,有 C 函数mallocfree While usually operator new and operator new[] just call malloc , this is not guaranteed.虽然通常operator newoperator new[]只是调用malloc ,但这并不能保证。 Therefore you may not mix those forms (eg by calling free on a pointer pointing to memory allocated with operator new ).因此,您不能混合使用这些形式(例如,通过在指向使用operator new分配的内存的指针上调用free )。 On the other hand, STL containers handle their allocations through allocators, which are objects which manage the allocation/deallocation of objects as well as construction/destruction of objects in containers.另一方面,STL 容器通过分配器处理它们的分配,分配器是管理对象的分配/释放以及容器中对象的构造/销毁的对象。

And finally, there are those objects whose lifetime is controlled directly by the language, namely those of static and automatic lifetime.最后,还有那些生命周期由语言直接控制的对象,即静态和自动生命周期的对象。 Automatic lifetime objects are allocated by simply defining a variable of the type at local scope.自动生命周期对象是通过在本地范围内简单地定义该类型的变量来分配的。 They are automatically created when execution passes that line, and automatically destroyed when execution leaves the scope (including it the scope is left through an exception).它们在执行通过该行时自动创建,并在执行离开作用域时自动销毁(包括通过异常离开作用域)。 Static lifetime objects are define at global/namespace scope or at local scope using the keyword static.静态生命周期对象使用关键字 static 在全局/命名空间范围或局部范围定义。 They are created at program startup (global/namespace scope) or when their definition line is forst executed (local scope), and they live until the end of the program, when they are automatically destroyed in reverse order of construction.它们在程序启动时(全局/命名空间作用域)或在它们的定义行被强制执行时(本地作用域)创建,并且它们一直存在到程序结束,当它们以与构造相反的顺序自动销毁时。

Generally, automatic or static variables are to be preferred to dynamic allocation (i,e, everything you allocate with new or allocators), because there the compiler cares for proper destruction, unlike dynamic allocation where you have to do that on your own.通常,自动或静态变量优先于动态分配(即,您使用new或分配器分配的所有内容),因为编译器关心适当的销毁,而动态分配则必须自己完成。 If you have dynamically allocated objects, it's desirable to have their lifetime managed by automatic/static objects (containers, smart pointers) for the same reason.如果您有动态分配的对象,出于同样的原因,希望它们的生命周期由自动/静态对象(容器、智能指针)管理。

You seem to have the operation of new correct in that it allocates and initializes memory.你似乎有new正确的操作,因为它分配和初始化内存。

Once the new completes successfully, you, the programmer, are responsible for delete ing that memory.一旦new成功完成,您,程序员,负责delete该内存。 The best way to make sure that this happens is to never use new directly yourself, instead preferring standard containers and algorithms, and stack-based objects.确保这种情况发生的最好方法是永远不要自己直接使用new ,而是更喜欢标准容器和算法以及基于堆栈的对象。 But if you do need to allocate memory, the C++ idiom is to use a smart pointer like unique_ptr from C++11 or shared_ptr from boost or C++11.但是,如果您确实需要分配内存,C++ 习惯用法是使用智能指针,如 C++11 中的unique_ptr或 boost 或 C++11 中的shared_ptr That makes sure that the memory is reclaimed properly.这可确保正确回收内存。

If an allocation fails, the new call will throw an exception after cleaning up any portion of the object that has been constructed prior to the failure.如果分配失败, new调用将在清除失败之前构造的对象的任何部分后抛出异常。 You can use the (nothrow) version of new to return a null pointer instead of throwing an exception, but that places even more burden of cleanup onto the client code.您可以使用 new 的(nothrow)版本来返回空指针而不是抛出异常,但这会给客户端代码带来更多的清理负担。

The new keyword The new operator is somewhat similar in the two languages. new 关键字 new 运算符在两种语言中有些相似。 The main difference is that every object and array must be allocated via new in Java.主要区别在于每个对象和数组都必须通过 Java 中的 new 分配。 (And indeed arrays are actually objects in Java.) So whilst the following is legal in C/C++ and would allocate the array from the stack... (实际上数组实际上是 Java 中的对象。)因此,虽然以下内容在 C/C++ 中是合法的,并且将从堆栈中分配数组......

 // C/C++ : allocate array from the stack
    void myFunction() {
      int x[2];
      x[0] = 1;
      ...
    }

...in Java, we would have to write the following: ...在 Java 中,我们必须编写以下内容:

// Java : have to use 'new'; JVM allocates
//        memory where it chooses.
void myFunction() {
  int[] x = new int[2];
  ...
}

ref: https://www.javamex.com/java_equivalents/new.shtml参考: https : //www.javamex.com/java_equivalents/new.shtml

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM