分配给 *this 以进行构造函数委托

发布于 2025-01-03 10:41:17 字数 530 浏览 1 评论 0原文

我正在研究 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;

返回这个,这是正确的。

42
84

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

I was looking at some of the new features in C++11, and due to my current version of GCC I am unable to use constructor delegation. But it got me thinking about replicating the feature like this:

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

    int num;
};

It certainly compiles and works fine, the code below:

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

Returns this, which is correct.

42
84

Obviously this is a very trivial example, but other than the memory inefficiencies (two A's created and one overwritten by the other before being destroyed), what problems could arise? It certainly looks like a code smell, but I can't think of a really good reason why.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

維他命╮ 2025-01-10 10:41:17

您不是用整数初始化对象,而是修改默认初始化的对象。这可能是也可能不是问题。人们经常在一些 init() 函数中分解出常见的东西,以具有与委托 ctor 类似的功能。然而,在某些情况下,这是不希望的/错误的/不可能的:

  • 当你有一个引用成员时,你必须在构造函数中初始化它,你不能默认初始化它并稍后覆盖。使用指针会有所帮助。
  • 对于某些成员,默认初始化会执行某些操作,而覆盖会执行其他操作。就性能而言,立即初始化成员会更有效。根据初始化的作用,这可能只是对性能的影响,但对于对象的某些副作用,它甚至可能是平面错误。
  • 该成员可能不可分配。

此外,有些人认为这是不好的风格。我个人认为这是不好的风格,因为我认为你应该总是初始化而不是稍后分配,即使对于简单的情况也是如此,因为有一天你忘记了一个重要的情况,然后性能的损失就会让你痛苦。

但是YMMV。

You are not initializing your object with the integer, but modifying a default initialized object. This might or might not be an issue. Quite often people factor common stuff out in some init() function to have similar functionality as delegating ctors. However, there are some situations in which this is not desired/wrong/impossible:

  • when you have a reference member, you must initialize this in the ctor, you can not default initialize it and later overwrite. Using a pointer instead can help.
  • for certain members, default initialization does something, and overwriting does something additional. Performance wise, it would have been more efficient to right away initialize the member. Depending on what the initialization does, this might just be a performance hit, but for certain side-effects of the object, it might even be plane wrong.
  • The member might not be assignable.

Additionally, this is just considered bad style by some people. I personally consider it bad style because I think you should always initialize instead of assign later, even for simple cases, since one day you forget it for an important case and then the lost performance bites you.

But YMMV.

那伤。 2025-01-10 10:41:17

您的代码实际上根本不是 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;
   }
};

您可以修改您的访问权限来品尝)。这里的问题是我只创建了一个“ABase”对象,如果它不仅仅是一个简单的 int 成员,那可能很重要。我非常喜欢继承,因为我然后在 A 中将它用作类成员而不是某个聚合对象的成员,并且我更喜欢这里的继承 protected 或 private,但有时如果基类有我想要公开的成员,我会使用公共继承,但为基类提供受保护的析构函数。这是假设没有 v 表,因此不需要进一步的推导。 (实际上,您可以通过将继承设为虚拟和私有来最终确定 A,但您可能不想这样做)。

Your code is not actually C++11 at all. I was thinking whether move constructors might work here as you are essentially moving one A into another then modifying it slightly.

As with C++03, you can optimise the initialisation you want to perform once in all your constructors either by putting them into a sub-class or a base-class (often with protected or private inheritance as it's an implementation detail). Using a base class:

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;
   }
};

(You can modify your access permissions to taste). The issue here is I only ever create one "ABase" object and if it has more than just a trivial int member, that might be significant. I quite like the inheritence as I then use it in A as a class member rather than a member of some aggregated object, and I prefer the inheritence protected or private here but sometimes if the base class has members I want to be public, I will use public inheritence but give the base class a protected destructor. This is assuming there is no v-table and thus no further derivation is expected. (You can finalize A here actually by making the inheritance virtual and private but you probably don't want to).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文