121

第 1 、 2 、 3 、 4 行有什么区别?

我什么时候使用每个?

为什么第 3 行打印constructor Foo并且第 7 行返回错误而第 8 行没有?

#include <iostream>     
using namespace std;

class Foo
 {
   public:
   Foo ( )
   {
      cout << "constructor Foo\n";
   }               
};

class Bar
 {
   public:
   Bar ( Foo )
   {
      cout << "constructor Bar\n";
   }
};

int main()
{
   /* 1 */ Foo* foo1 = new Foo ();
   /* 2 */ Foo* foo2 = new Foo;
   /* 3 */ Foo foo3;
   /* 4 */ Foo foo4 = Foo::Foo();

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );
   /* 6 */ Bar* bar2 = new Bar ( *new Foo );
   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

   return 1;
}
4

3 回答 3

143
   /* 1 */ Foo* foo1 = new Foo ();

Foo在动态内存中创建一个类型的对象。foo1指向它。通常,您不会在 C++ 中使用原始指针,而是使用智能指针。如果Foo是 POD 类型,这将执行值初始化(此处不适用)。

   /* 2 */ Foo* foo2 = new Foo;

与之前相同,因为Foo不是 POD 类型。

   /* 3 */ Foo foo3;

创建一个在自动存储中调用的Foo对象。foo3

   /* 4 */ Foo foo4 = Foo::Foo();

使用复制初始化来创建一个在自动存储中Foo调用的对象。foo4

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );

使用Bar的转换构造函数Bar在动态存储中创建类型的对象。bar1是指向它的指针。

   /* 6 */ Bar* bar2 = new Bar ( *new Foo );

和之前一样。

   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );

这只是无效的语法。你不能在那里声明一个变量。

   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

如果bar3未在 7 中声明,将按照相同的原则对 5 和 6 工作和工作。

5 & 6包含内存泄漏。

类似的语法new Bar ( Foo::Foo() );并不常见。通常是new Bar ( (Foo()) );——额外的括号是最令人头疼的解析。(更正)

于 2012-09-03T13:24:34.420 回答
24
  1. 从空闲存储中分配一些动态内存,并使用其默认构造函数在该内存中创建一个对象。你永远不会删除它,所以内存泄漏了。
  2. 与 1 完全相同;在用户定义类型的情况下,括号是可选的。
  3. 分配一些自动内存,并使用其默认构造函数在该内存中创建一个对象。当对象超出范围时,内存会自动释放。
  4. 与 3 类似。名义上,命名对象foo4是通过默认构造、复制和销毁临时对象来初始化的;通常,这会被省略,得到与 3 相同的结果。
  5. 分配一个动态对象,然后通过复制第一个对象来初始化第二个对象。两个对象都泄漏了;并且没有办法删除第一个,因为您没有保留指向它的指针。
  6. 与5完全一样。
  7. 不编译。Foo foo5是声明,不是表达式;函数(和构造函数)参数必须是表达式。
  8. 创建一个临时对象,并通过复制来初始化一个动态对象。只有动态对象被泄露;临时在完整表达式结束时自动销毁。请注意,您可以使用 justFoo()而不是等效Foo::Foo()(或确实Foo::Foo::Foo::Foo::Foo())创建临时

我什么时候使用每个?

  1. 不要,除非您喜欢在代码上进行不必要的装饰。
  2. 当您想要创建一个超出当前范围的对象时。用完记得删除它,学习如何使用智能指针更方便地控制生命周期。
  3. 当您想要一个仅存在于当前范围内的对象时。
  4. 不要,除非你觉得 3 看起来很无聊,什么添加一些不必要的装饰。
  5. 不要,因为它会泄漏内存而没有恢复的机会。
  6. 不要,因为它会泄漏内存而没有恢复的机会。
  7. 不要,因为它不会编译
  8. 当您想Bar从临时Foo.
于 2012-09-03T14:19:49.847 回答
5

第 1、2、3、4 行将调用默认构造函数。它们本质上是不同的,因为 1,2 是动态创建的对象,而 3,4 是静态创建的对象。

在第 7 行,您在参数调用中创建了一个对象。所以这是一个错误。

第 5 行和第 6 行是内存泄漏的邀请。

于 2012-09-03T13:25:42.313 回答