这是好的代码吗? (复制构造函数和赋值运算符)
由于某种原因,我被迫为我的类提供复制构造函数和运算符=。我认为如果我定义了一个复制构造函数,我就不需要 operator=
,但是 QList
需要一个。撇开这一点不谈,我讨厌代码重复,那么这样做有什么问题吗?
Fixture::Fixture(const Fixture& f) {
*this = f;
}
Fixture& Fixture::operator=(const Fixture& f) {
m_shape = f.m_shape;
m_friction = f.m_friction;
m_restitution = f.m_restitution;
m_density = f.m_density;
m_isSensor = f.m_isSensor;
return *this;
}
只是出于好奇,没有办法切换它以便大部分代码都在复制构造函数中并且 operator=
以某种方式利用它?我尝试了 return Fixture(f);
但它不喜欢那样。
看来我需要更清楚地表明,复制构造函数和赋值运算符已被我继承的类隐式禁用。为什么?因为它是一个抽象基类,不应自行实例化。然而,这个类是独立的。
For one reason or another, I'm forced to provide both a copy constructor and an operator= for my class. I thought I didn't need operator=
if I defined a copy ctor, but QList
wants one. Putting that aside, I hate code duplication, so is there anything wrong with doing it this way?
Fixture::Fixture(const Fixture& f) {
*this = f;
}
Fixture& Fixture::operator=(const Fixture& f) {
m_shape = f.m_shape;
m_friction = f.m_friction;
m_restitution = f.m_restitution;
m_density = f.m_density;
m_isSensor = f.m_isSensor;
return *this;
}
And just out of curiosity, there's no way to switch it so that the bulk of the code is in the copy ctor and operator=
somehow utilizes it? I tried return Fixture(f);
but it didn't like that.
It appears I need to make it more clear that the copy constructor and assignment operator have been implicitly disabled by the class I am inheriting from. Why? Because it's an abstract base class that shouldn't be instantiated on its own. This class, however, is meant to stand alone.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这很糟糕,因为
operator=
不能再依赖于设置对象。您应该以相反的方式进行操作,并且可以使用复制交换习惯用法。如果您只需复制所有元素,则可以使用隐式生成的赋值运算符。
在其他情况下,您将必须额外执行一些操作,主要是释放和复制内存。这就是复制交换习惯用法的用武之地。它不仅很优雅,而且还提供了这样的功能:如果只交换基元,则赋值不会引发异常。让我们创建一个指向需要复制的缓冲区的类:
这就是我通常编写赋值运算符的方式。阅读想要速度?按值传递关于异常赋值运算符签名(按值传递)。
This is bad, because the
operator=
can't rely on a set-up object anymore. You should do it the other way around, and can use the copy-swap idiom.In the case where you just have to copy over all elements, you can use the implicitly generated assignment operator.
In other cases, you will have to do something in addition, mostly freeing and copying memory. This is where the copy-swap idiom is good for. Not only is it elegant, but it also provide so an assignment doesn't throw exceptions if it only swaps primitives. Let's a class pointing to a buffer that you need to copy:
That's how i write the assignment operator usually. Read Want speed? Pass by value about the unusual assignment operator signature (pass by value).
复制构造函数和赋值是完全不同的——赋值通常需要释放它正在替换的对象中的资源,复制构造函数正在处理尚未初始化的对象。由于在这里您显然没有特殊要求(作业时不需要“释放”),因此您的方法很好。更一般地说,您可能有一个“释放对象持有的所有资源”辅助方法(在 dtor 中和分配开始时调用)以及相当接近的“将这些其他内容复制到对象中”部分典型抄袭者的作品(或者大部分,无论如何;-)。
Copy ctor and assignment are entirely distinct -- assignment typically needs to free resources in the object that it's replacing, copy ctor is working on a not-yet-initialized object. Since here you apparently have no special requirements (no "releasing" needed on assignment), your approach is fine. More in general, you might have a "free all resources the object is holding" auxiliary method (to be called in the dtor and at the start of assignment) as well as the "copy these other things into the object" part that's reasonably close to the work of a typical copy ctor (or mostly, anyway;-).
您只需在示例中进行成员明智的复制和分配。这不是你需要自己写的东西。编译器可以生成隐式复制和赋值操作来执行此操作。如果编译器生成的复制构造函数、赋值函数和/或析构函数不合适(即,如果您通过指针或类似的东西管理某些资源),您只需要编写自己的复制构造函数、赋值函数和/或析构函数。
You're simply doing a member-wise copy and assignment in your examples. This is not something you need to write yourself. The compiler can generate implicit copy and assignment operations that do exactly that. You only need to write your own copy constructor, assignment and/or destructor if the compiler-generated ones are not appropriate (i.e. in case you manage some resource through a pointer or something like that)
我认为如果您的操作员=变得虚拟,您会遇到问题。
我建议编写一个函数(可能是静态的)来执行复制,然后让复制构造函数和运算符 = 调用该函数。
I think you run into issues if your operator= ever becomes virtual.
I would recommend writing a function (maybe static) that does the copy then have the copy-constructor and operator= call that function instead.
是的,这是一个很好的做法,应该(几乎)始终这样做。此外,还添加了析构函数和默认构造函数(即使您将其设为私有)。
在 James Coplien 1991 年的书高级 C++ 中,这被描述为“正统”的一部分规范形式”。在其中,他提倡使用默认构造函数、复制构造函数、赋值运算符和析构函数。
Coplien 提供了很多关于这种模式的原因,但我无法在这里公正地解释它们。然而,已经涉及的一个关键项目是清理被覆盖的对象的能力。
Yes, this is good practice and should (almost) always be done. In addition toss in a destructor and default constructor (even if you make it private).
In James Coplien's 1991 book Advanced C++, this is described as part of "Orthodox Canonical Form". In it, he advocates for a default constructor, a copy constructor, the assignment operator and a destructor.
Coplien offers pages of reasons for this pattern and I couldn't do them justice here. However, a key item that has already been touched on is the ability to clean up the object that is being overwritten.
我认为你应该使用初始化列表来初始化你的对象成员变量。如果您的变量是
原始类型
,那么这并不重要。否则,赋值与初始化不同。您可以通过将复制构造函数内的指针初始化为
0
来实现这一点,然后您可以在赋值运算符
中安全地调用delete:I think you should initialize your object member variables using
initializer list
. If your variables are ofprimitive-types
, then it doesn't matter. Otherwise, assignment is different from initialization.You could do it with a little trick by initializing pointers inside the
copy constructor
to0
, then you could call delete safely in theassignment operator
: