谁删除了 + 中复制的实例操作员 ? (c++)

发布于 2024-09-02 06:34:40 字数 644 浏览 2 评论 0原文

我在互联网上搜索了如何正确实现 + 运算符,我发现的所有结果都执行以下步骤:

const MyClass MyClass::operator+(const MyClass &other) const
{
    MyClass result = *this;  // Make a copy of myself. Same as MyClass result(*this);
    result += other;         // Use += to add other to the copy.
    return result;           // All done!
}

我对这个“过程”有几个疑问:

  1. 以这种方式实现 + 运算符不是很愚蠢吗?第一行中的赋值运算符(复制类),然后是返回中的复制构造函数(它也复制类,由于返回是按值传递的,因此它会销毁第一个副本并创建一个新副本.. 坦率地说,这并不是很聪明...)

  2. 当我写 a= b+c,b+c 部分创建该类的新副本,然后 'a=' 部分将该副本复制给自己。 谁删除了 b+c 创建的副本?

  3. 是否有更好的方法来实现 + 运算符,而无需两次处理该类,并且也没有任何内存问题?

提前致谢

I searched how to implement + operator properly all over the internet and all the results i found do the following steps :

const MyClass MyClass::operator+(const MyClass &other) const
{
    MyClass result = *this;  // Make a copy of myself. Same as MyClass result(*this);
    result += other;         // Use += to add other to the copy.
    return result;           // All done!
}

I have few questions about this "process" :

  1. Isn't that stupid to implement + operator this way, it calls the assignment operator(which copies the class) in the first line and then the copy constructor in the return (which also copies the class , due to the fact that the return is by value, so it destroys the first copy and creates a new one.. which is frankly not really smart ... )

  2. When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself.
    who deletes the copy that b+c created ?

  3. Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?

thanks in advance

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

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

发布评论

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

评论(8

沉鱼一梦 2024-09-09 06:34:40
  1. 这实际上不是赋值运算符,而是复制构造函数。毕竟,像加法这样的操作会创建一个新值,因此必须在某个地方创建它。这比看起来更有效,因为编译器可以自由地进行返回值优化,这意味着它可以直接在接下来使用的地方构造值。

  2. 结果被声明为局部变量,因此会随着函数调用而消失 - 除非使用 RVO(见上文),在这种情况下,它从未在函数中实际创建,但在调用者中。

  3. 并非如此;这种方法比乍一看要高效得多。

  1. That's effectively not an assignment operator, but a copy constructor. An operation like addition creates a new value, after all, so it has to be created somewhere. This is more efficient than it seems, since the compiler is free to do Return Value Optimization, which means it can construct the value directly where it will next be used.

  2. The result is declared as a local variable, and hence goes away with the function call - except if RVO (see above) is used, in which case it was never actually created in the function, but in the caller.

  3. Not really; this method is much more efficient than it looks at first.

旧竹 2024-09-09 06:34:40

在这种情况下,我可能会考虑这样的事情:

MyClass MyClass::operator+(MyClass other) { 
     other += *this;
     return other;
}

Dave Abrahams 写了一个 文章 不久前解释了它是如何工作的以及为什么这种代码通常非常有效,尽管最初看起来不应该如此。

编辑(谢谢 MSalters):是的,这确实假设/取决于 MyClass 的交换属性。如果 a+b != b+a,那么原始代码就是您想要的(大多数相同的推理适用)。

Under the circumstances, I'd probably consider something like:

MyClass MyClass::operator+(MyClass other) { 
     other += *this;
     return other;
}

Dave Abrahams wrote an article a while back explaining how this works and why this kind of code is usually quite efficient even though it initially seems like it shouldn't be.

Edit (thank you MSalters): Yes, this does assume/depend upon the commutative property holding for MyClass. If a+b != b+a, then the original code is what you want (most of the same reasoning applies).

夕色琉璃 2024-09-09 06:34:40

它在第一行调用赋值运算符(复制类)

不,这是复制初始化(通过构造函数)。

然后是返回中的复制构造函数(它也复制类

编译器可以(并且通常会)使用 NRVO 删除此副本。

当我写 a=b+c 时,b+c 部分创建该类的新副本,然后 'a=' 部分将该副本复制给自己。谁删除了 b+c 创建的副本

编译器,就像任何其他临时值一样。它们在完整表达式的末尾被删除(在本例中,这意味着行尾的 ; 处或之后。

是否有更好的方法来实现 + 运算符,而无需两次处理该类,并且不会出现任何内存问题?

并不真地。这并不是那么低效。

it calls the assignment operator(which copies the class) in the first line

No, this is copy-initialization (through constructor).

then the copy constructor in the return (which also copies the class

Compilers can (and typically do) elide this copy using NRVO.

When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself. who deletes the copy that b+c created

The compiler, as any other temporary value. They are deleted at the end of full-expression (in this case, it means at or after ; at the end of line.

Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?

Not really. It's not that inefficient.

雨后彩虹 2024-09-09 06:34:40

这似乎是实现operator+的正确方法。几点:

  • MyClass result = *this 没有使用赋值运算符,它应该调用复制构造函数,就像写MyClass result(*this)一样。
  • a = b + c中使用时的返回值称为临时,编译器负责删除它(这可能会发生在语句末尾,即. 分号,在完成其他操作之后)。你不必担心这一点,编译器总是会清理临时文件。
  • 没有更好的办法了,你需要副本。然而,编译器可以优化临时副本,因此不会像您想象的那样多。但在 C++0x 中,您可以使用移动构造函数通过转移临时内容的所有权而不是复制整个内容来提高性能。

This appears to be the correct way to implement operator+. A few points:

  • MyClass result = *this does not use the assignment operator, it should be calling the copy constructor, as if it were written MyClass result(*this).
  • The returned value when used in a = b + c is called a temporary, and the compiler is responsible for deleting it (which will probably happen at the end of the statement ie. the semicolon, after everything else has been done). You don't have to worry about that, the compiler will always clean up temporaries.
  • There's no better way, you need the copy. The compiler, however, is allowed to optimise away the temporary copies, so not as many as you think may be made. In C++0x though, you can use move constructors to improve performance by transfering ownership of the content of a temporary rather than copying it in its entirity.
双马尾 2024-09-09 06:34:40

我会尽力回答:

第(1)点:不,它不会调用赋值运算符。相反,它调用构造函数。由于无论如何您都需要构造对象(因为 operator+ 返回一个副本),因此这不会引入额外的操作。

第(2)点:临时结果是在堆栈中创建的,因此不会引入内存问题(当函数退出时它会被销毁)。在返回时,会创建一个临时变量,以便可以使用赋值(或复制构造函数)将结果分配给a(在a=b+c;中)。),即使在结果被销毁之后。这个临时文件会被编译器自动销毁。

第(3)点:以上是标准的规定。请记住,只要效果与标准规定的相同,编译器实现者就可以优化实现。我相信,编译器实际上优化了这里发生的许多复制。使用上面的习惯用法是可读的,而且实际上并不是低效的。

PS 我有时更喜欢将 operator+ 实现为非成员,以利用运算符两侧的隐式转换(仅当有意义时)。

I'll try my best to answer:

Point (1): No, it does not call the assignment operator. Instead it calls a constructor. Since you need to construct the object anyway (since operator+ returns a copy), this does not introduce extra operations.

Point (2): The temporary result is created in stack and hence does not introduce memory problem (it is destroyed when function exits). On return, a temporary is created so that an assignment (or copy constructor) can be used to assign the results to a (in a=b+c;) even after result is destroyed. This temporary is destroyed automatically by the compiler.

Point (3): The above is what the standard prescribes. Remember that compiler implementors are allowed to optimize the implementation as long as the effect is the same as what the standard prescribed. I believe, compilers in reality optimize away many of the copying that occurs here. Using the idiom above is readable and is not actually inefficient.

P.S. I sometime prefer to implement operator+ as a non-member to leverage implicit conversion for both sides of the operators (only if it makes sense).

旧故 2024-09-09 06:34:40

不存在内存问题(前提是赋值运算符和复制构造函数写得好)。原因很简单,因为这些对象的所有内存都放在堆栈上并由编译器管理。此外,编译器确实对此进行了优化,并直接在最终的a 上执行所有操作,而不是复制两次。

There are no memory issues (provided that the assignment operator, and copy constructor are well written). Simply because all the memory for these objects is taken on the stack and managed by the compiler. Furthermore, compilers do optimize this and perform all the operations directly on the final a instead of copying twice.

一场信仰旅途 2024-09-09 06:34:40
  1. 这是在 C++ 中实现运算符+的正确方法。您所担心的大多数副本都会被编译器删除,并且会受到 C++0x 中移动语义的影响。

  2. 该课程是临时课程,将被删除。如果将临时对象绑定到 const&,临时对象的生命周期将延长到 const 引用的生命周期。

  3. 可能将其实现为自由函数会更明显一些。 MyClass::operator+ 中的第一个参数是隐式的 this,编译器无论如何都会将该函数重写为 operator+(const MyClass&, const MyClass&)。

  1. This is the proper way of implementing the operator+ in C++. Most of the copies you are so afraid of will get elided by the compiler and will be subject to move semantics in C++0x.

  2. The class is a temporary and will be deleted. If you bind the temporary to a const& the life time of the temporary will be extended to the life time of the const reference.

  3. May implementing it as a freefunction is a little more obvious. The first parameter in MyClass::operator+ is an implicit this and the compiler will rewrite the function to operator+(const MyClass&, const MyClass&) anyway.

长不大的小祸害 2024-09-09 06:34:40

据我所知,Stroustrup 的《C++ 编程语言》建议仅当内部表示受到操作影响时将运算符实现为成员函数,而在不受操作影响时将运算符实现为外部函数。如果基于operator+= 实现,operator+ 不需要访问内部表示,但确实如此。

所以你会:

class MyClass
{
public:
  MyClass& operator+=(const MyClass &other)
  {
    // Implementation
    return *this;
  }
};

MyClass operator+(const MyClass &op1, const MyClass &op2)
{
    MyClass r = op1;
    return r += op2;
}

As far as I remember, Stroustrup's 'The C++ Programming Language' recommends to implement operators as member functions only when internal representation is affected by operation and as external functions when not. operator+ does not need to access internal representation if implemented based on operator+=, which does.

So you would have:

class MyClass
{
public:
  MyClass& operator+=(const MyClass &other)
  {
    // Implementation
    return *this;
  }
};

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