我熟悉的原则(例如,从这个答案和这一个),当一个类有一个移动构造函数和/或移动赋值操作符,其默认的拷贝构造函数和拷贝赋值运算符将被删除。但是,在我看到的示例中,可以通过显式定义新的副本构造函数和赋值运算符来解决此问题。
在我的特定情况下,我有一个类,该类是从C样式结构和模板类的联合继承派生的。复制和移动分配运算符在模板中显式定义,而复制和移动构造函数在类本身中显式定义。换句话说,所有内容都是明确定义的,尽管不是全部都在同一位置。这是一些示例代码:
typedef struct {
int n;
} myStruct;
template <typename T> class myTemplate
{
public:
// Default constructor
myTemplate<T>() : t_n(nullptr) {}
// Cannot create copy or move constructors in template, as cannot
// access the 'n' member directly
// Copy assignment operator
myTemplate<T> & operator=(const myTemplate<T> &source)
{
if (this != &source)
{
*t_n = *(source.t_n);
}
return *this;
}
//! Move assignment operator
myTemplate<T> & operator=(myTemplate<T> &&source)
{
if (this != &source)
{
*t_n = *(source.t_n);
*(source.t_n) = 0;
source.t_n = nullptr;
}
return *this;
}
T* t_n;
};
class myClass : public myStruct, public myTemplate<int>
{
public:
// Default constructor
myClass() : myTemplate<int>()
{
n = 0;
t_n = &n;
}
// Alternative constructor
myClass(const int &n_init) : myTemplate<int>()
{
n = n_init;
t_n = &n;
}
// Copy constructor
myClass(const myClass &source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
}
// Move constructor
myClass(myClass &&source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
source.n = 0;
source.t_n = nullptr;
}
};
int main()
{
myClass myObject(5);
myClass myOtherObject;
// Compilation error here:
myOtherObject = myObject;
return 1;
}
在Windows上的Visual C ++和Intel C ++中,这完全可以按照我的预期工作。但是,在Linux上的gcc 4.9.0上,我得到了可怕的错误消息:
g++ -c -std=c++11 Main.cppMain.cpp: In function ‘int main()’:
Main.cpp:78:19: error: use of deleted function ‘myClass& myClass::operator=(const myClass&)’
myOtherObject = myObject;
^
Main.cpp:39:7: note: ‘myClass& myClass::operator=(const myClass&)’ is implicitly declared as deleted because ‘myClass’ declares a move constructor or move assignment operator
class myClass : public myStruct, public myTemplate<int>
可以肯定的是,如果我在类本身而不是模板中定义一个显式的复制赋值运算符,该错误就会消失,但是这样做很麻烦,并且削弱了使用模板的优势,因为(a)我实际的复制赋值运算符是比这里显示的要大得多,并且(b)有许多不同的类都共享此模板。
那么,这仅仅是gcc 4.9.0中的一个bug,还是事实上标准所说的会发生?
GCC是正确的(Clang和EDG同意)。
myTemplate
具有用户声明的move构造函数,因此将其副本分配运算符删除。
您提供了一个复制构造函数,但没有提供复制赋值运算符。只需声明一个复制赋值运算符myTemplate
并将其定义为默认值即可。这需要多一行代码。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句