int i = 0,int i(0),int * p = new int,int * p = c中的新int(0)有什么区别

时间:2013-03-12 01:49:31

标签: c++

之间有什么区别
int i=0; 

int i(0);

int *p=new int; 

int *p=new int(0);

int *p=new int仍然是复制初始样式吗?

何时使用int i=0;而不是new int(0)

4 个答案:

答案 0 :(得分:5)

我先回答一个稍微不同的问题。

假设您有classstruct(它们几乎相同),如下所示:

struct Foo {
  int value; // Foo stores an int, called value
  Foo(int v):value(v) {}; // Foo can be constructed (created) from an int
  explicit Foo(double d):value(d) {}; // Foo can be constructed (created) from a double
  // ^^^ note that keyword.  It says that it can only be EXPLICITLY created from a double
};

现在,这很像int,但存在一些差异。

Foo i = 0;

上面创建了一个int文字,然后使用Foo i构造函数构建Foo(int v)

Foo i(0);

上面创建了一个int文字,然后使用Foo i构造函数构建Foo(int v)。请注意,我只是重复了一遍。

Foo i = Foo(0);

上面创建了一个int文字,然后使用Foo i构造函数构建Foo(int v),然后从中复制构造Foo i。但是,该标准允许编译器" elide" (跳过)复制构造函数,而只是直接从Foo i文字int构建0

Foo* i = new Foo;

这将转到免费存储(通常实现并称为堆),获取足够的内存来存储Foo,然后默认构造它。然后它返回此Foo对象的地址,然后用于初始化指针Foo* i。现在,请注意Foo的默认构造函数使value 未初始化。这是我在Foo上面实现的一个缺陷(在我看来),除非在特殊情况下你很少想要这样做。

恼人地,整数(charintlongunsigned char等),浮点(doublefloat)文字和指针文字都共享此属性 - 默认情况下,它们不会初始化为任何值。

因此,您应确保明确初始化它们。如果是Foo,请添加一行:

Foo():value() {}

就足够了。

Foo* i = new Foo(0);

这将转到免费存储(通常实现并称为堆),获取足够的内存来存储Foo,然后使用整数文字0构造它。然后返回此{{的地址1}} object,然后用于初始化指针Foo

现在,免费商店中的内存通常一直保留供您使用,直到您回复它或程序关闭为止。为了返回它,你在相同的指针上调用Foo* i,这两个情况下的对象(在这种情况下为delete)使其析构函数被调用(Foo没有析构函数,所以这被跳过),然后将内存传回免费商店,供以后调用Foo时使用。

跟踪这是一个真正的痛苦,并且是一大堆错误的来源,所以你应该避免调用new。有许多方法可以避免调用new,包括使用new来管理内存块,或使用std::vectorshared_ptr在堆上创建管理其自身生命周期的对象通过一种称为RAII的技术,或者当你想要对指针的生命周期进行严密控制时使用make_shared(遗憾的是,unique_ptr不存在)。

现在让我们走得更远。

make_unique

无法编译。我说Foo i = 0.0; 的构造函数是显式的,上面只选择调用非显式的构造函数。另一方面:

Foo(double)

这两者都愿意调用显式构造函数,并且工作正常。

接下来,C ++ 11为我们带来了统一的初始化。你可以把它放在Foo i(0.0); Foo i = Foo(0.0); - 一个波浪形的大括号里,而不是把你想要的东西用()初始化。

{}

等。 Foo i{0.0}; Foo i = {0}; 与基于{}的语法相比有一些差异 - 最重要的是它避免了most vexing parse个问题。其他差异包括初始化列表行为,处理显式琐碎构建的内容(()不会构建名为int x()的{​​{1}},但int会这样做。

说到这一点,是时候回到你的实际问题了。

x在某些方面与我的int x{}不同。

首先,它不是intstruct Foo。因此,它的行为而不是由您编写的某些代码确定,而是由标准广泛描述。碰巧的是,C ++尝试让像class这样的原始类型表现得像struct之类的简单用户定义类型,这很有用。

所以虽然没有"复制构造函数"被调用,int根本没有构造函数或析构函数,Foo几乎完全表现为"好像"那里有这样的建设者。

int

创建整数文字0,然后用它初始化int。编译器可能会忽略它,只需直接创建值为0的整数int i = 0; 。对于int i,无法直接观察差异。

int i

int相同,因为int i(0); 没有非显式构造函数。这只是一种不同的语法。

现在,存在最令人烦恼的解析问题。如果你输入

int i = 0

您与int相同,但如果您输入

int i = int();

将会发生的事情是编译器会说"这可能是一个名为i的函数,它带有零参数并返回int i = 0",并且出于各种令人讨厌的原因,优先选择解释为默认值 - 初始化int i(); 。因此,您将获得一个名为int的前向声明函数,而不是整数。

如前所述,避免这种情况的方法是始终使用以下语法:

int

在C ++ 11编译器中。

接下来,我们有

i

在免费商店中创建默认构造(未初始化)int i{}; ,并将指针指向变量int* p = new int; 。已发生副本,但它是指针的副本,而不是int

int *p

大致相同,但创建的免费商店int的值为0而不是未初始化。

在这两种情况下,您都有责任仅对int *p=new int(0); 返回的值调用一次int。不这样做被称为内存泄漏。执行此操作后使用指针值会导致未定义的行为,通常会导致内存损坏。你几乎肯定不会被程序警告你所做的事情是危险的,但是你的程序现在可以做完全随机的事情,这些事情毫无意义,仍然是一个有效的C ++程序。将每个delete与一个new对齐,并确保没有人在new之后使用指针,并尽早调用delete,这是一个令人烦恼的程序,整个已经开发了各种编程语言,其主要销售特征是它们使开发人员不必处理它。

因此,请避免致电delete

哦,因为这还不够长,请注意我使用最烦人的解析"以上不太正确。最令人烦恼的解析"实际上是:

delete

而不是

new

因为第一个可能是构造函数调用或函数,而第二个不能是构造函数调用,因为标准不允许它。

然而,我和其他大多数人都发现了int x(int()); 的解析规则,所以称之为倒数第二个烦恼的解析,你就不会错。它仍然没有做你天真以为它应该做的事情(创建一个默认的构造int x(); ),所以这很麻烦。

答案 1 :(得分:2)

在C和早期C ++中,你只能使用int i = 0;

int i(0);模式与一般类型

的构造函数相同
T i(0);

所以它被添加为int i=0;的替代,它看起来不像一般的构造函数模式。这在使用模板时很有用。所以模板可以使用int和类。

答案 2 :(得分:2)

int i=0; 
int i(0);

这些是相同的,有两种不同的初始化语法(C-类似第一种,构造函数式第二种);根据原则,它们在处理类时略有不同(第一个暗示 - 可能是省略的 - 调用复制构造函数,第二个不是),但对于int s它们实际上是相同的。 / p>

int *p=new int; 
int *p=new int(0);

在第一个中,int未初始化(它将具有在该内存位置发生的任何值);在第二种情况下,int被初始化为0.

但最重要的是,这些是与第一种完全不同的两种野兽。您没有声明int类型的自动变量,而是指针int,它指向两个动态分配的 int s

区别很深:使用int i=0自动管理内存(它具有自动存储持续时间),当变量超出范围时,变量将被销毁;使用new从freestore(所谓的堆)中分配内存,它没有自动释放方法 - 你必须显式释放它(使用delete,尽管在现代C ++智能指针中通常用于自动管理动态对象的生命周期。)

new通常用于自动存储持续时间不是一个好选择的情况(例如,您希望那些int比当前范围更长,或者在多个对象之间共享或无论什么)或当你分配的东西太大而无法保留在局部变量中时(在典型的实现中,局部变量会进入堆栈,这在大小上是有限的;对于两个int来说,这不是一个有效的问题)。

对于“常规”,必须与当前范围int“死”的本地new变量通常不是一个好主意。

尽管如此,有关动态分配的更多信息,请查看您的C ++书籍。

答案 3 :(得分:-1)

new意味着堆内存分配(可能泄漏),所以不,你不想一直这样做。

int i=0;int i(0);是等价的,但是根据实现,第一个可以使用赋值运算符,而第二个可以使用值构造。这可以让编译器针对目标体系结构进行优化。在类的情况下,赋值方法可能较慢,因为它将创建一个类(通常使用默认值),然后它将通过一个赋值并清除它刚刚花费时间分配的所有默认值。

有人可能会参与语言规范并获得更准确的答案。