C++ 为构造函数委派分配给*

C++ 为构造函数委派分配给*,c++,constructor,c++11,this,delegation,C++,Constructor,C++11,This,Delegation,我正在研究C++11中的一些新特性,由于我当前的GCC版本,我无法使用构造函数委托。但这让我想到复制这样的功能: class A { public: A() : num( 42 ) {} A( int input ) { *this = A(); num *= input; } int num; }; 它当然可以编译并运行良好,代码如下: A a; cout << "a: " << a.num << endl; A b( 2 );

我正在研究C++11中的一些新特性,由于我当前的GCC版本,我无法使用构造函数委托。但这让我想到复制这样的功能:

class A
{
public:
    A() : num( 42 ) {}
    A( int input ) { *this = A(); num *= input; }

    int num;
};
它当然可以编译并运行良好,代码如下:

A a;
cout << "a: " << a.num << endl;
A b( 2 );
cout << "a: " << b.num << endl;

显然,这是一个非常微不足道的例子,但除了内存效率低下(创建了两个
a
,一个在销毁前被另一个覆盖)之外,还会出现什么问题?这看起来确实像是代码的味道,但我想不出一个真正好的理由。

您不是在用整数初始化对象,而是在修改默认的初始化对象。这可能是个问题,也可能不是。通常,人们会在一些
init()
函数中考虑常见的内容,以使其具有与委托人类似的功能。但是,在某些情况下,这是不需要的/错误的/不可能的:

  • 当您有一个引用成员时,您必须在ctor中初始化它,您不能默认初始化它并稍后覆盖。相反,使用指针会有所帮助
  • 对于某些成员,默认初始化会执行某些操作,而覆盖会执行其他操作。就性能而言,立即初始化成员会更有效。根据初始化所做的工作,这可能只是性能上的一个打击,但对于对象的某些副作用,它甚至可能是错误的
  • 该成员可能不可分配
此外,有些人认为这是一种糟糕的风格。我个人认为它是坏的风格,因为我认为你应该总是初始化,而不是以后分配,即使是简单的情况下,因为有一天你忘记了一个重要的情况,然后失去的性能咬你。
但是YMMV。

您的代码实际上根本不是C++11。我在想移动构造函数是否可以在这里工作,因为您实际上是将一个A移动到另一个A,然后稍微修改它

与C++03一样,您可以通过将构造函数放入子类或基类(通常带有保护继承或私有继承,这是一个实现细节)来优化要在所有构造函数中执行一次的初始化。使用基类:

class ABase
{
protected:
  int num;

  ABase() : num(42) {}
};

class A : protected ABase
{
public:
   A() = default; // or in C++03 just {}
   explicit A(int input) : ABase()
   {
       num *= input;
   }
};

(您可以修改您的访问权限以使用taste)。这里的问题是,我只创建了一个“ABase”对象,如果它不仅仅有一个微不足道的int成员,那么这可能是非常重要的。我非常喜欢继承,因为我在中使用它作为类成员,而不是某个聚合对象的成员,我更喜欢这里的继承受保护或私有,但有时如果基类有成员我希望是公共的,我将使用公共继承,但给基类一个受保护的析构函数。这是假设不存在v表,因此不需要进一步推导。(您可以通过将继承设置为虚拟的和私有的,在这里完成一个实例,但您可能不想这样做)。

顺便说一句,GCC 4.7将有构造函数委托(它已经在主干中)我知道,这个问题真的是出于好奇。我当前运行的是v4.6,我将等待发行版升级,然后才能“正确”执行此操作。不可分配的类型是否有限制:)?(有了移动分配,它不太可能经常出现)。你有没有想过新的(这)一个?(我不知道这是否是远程有效的,但避免了内存分配-虽然看起来更脏:)@Mat:这是无效的(您可能只会将新的对象放置到原始内存中,那里已经存在对象),在您建议在此之前调用dtor之前,阅读相应的gotw,了解为什么这是异常安全的毒药。我目前正在使用init()函数,但我希望有一个更干净的习惯用法,但没有找到!谢谢你的回答。我知道我的示例代码不是C++11——这是本文的重点(模拟C++11之前的构造函数委托)。您的解决方案确实解决了初始化引用的问题(在
init()
函数中无法完成),但它也需要更多的LOC和额外的类型。
class ABase
{
protected:
  int num;

  ABase() : num(42) {}
};

class A : protected ABase
{
public:
   A() = default; // or in C++03 just {}
   explicit A(int input) : ABase()
   {
       num *= input;
   }
};