我遇到了一个问题,因为当有一个用户定义的析构函数时,C ++ 11默认生成复制构造函数和复制赋值运算符,因此处于弃用状态。
对于大多数足够简单的类,默认生成的构造函数,运算符和析构函数都可以。请考虑以下原因来声明析构函数:
在基类中创建虚拟析构函数:
// header
class Base1 { public: virtual ~Base1() = default; };
class Base2 { public: virtual ~Base2(); };
// source
Base2::~Base2() = default;
在这些情况下,编译器是否会生成4个复制和移动特殊方法?如果是,那么我认为没关系,Base1
或Base2
没有问题。
在析构函数中打印调试消息:
// header
class D { public: ~D(); };
// source
D::~D() {
#ifdef DEBUG_THIS
std::cout << "D was destructed." << std::endl;
#endif
}
我相信在这种情况下会生成复制构造函数和赋值运算符;但移动构造函数和赋值运算符不会。我想避免使用已弃用的默认生成并禁用D
的复制。我还想避免使用4 D
声明来充斥deleted
。是否仅禁用一个复制构造函数?这是一种好风格吗?
答案 0 :(得分:15)
使用C ++ 11,一种干净的方法是遵循boost中使用的模式(参见here)
您基本上创建了一个基类,其中复制构造函数和复制赋值被删除,并继承它:
class non_copyable
{
protected:
non_copyable() = default;
~non_copyable() = default;
non_copyable(non_copyable const &) = delete;
void operator=(non_copyable const &x) = delete;
};
class MyClass: public non_copyable
{
...
}
答案 1 :(得分:12)
删除复制构造函数和复制赋值运算符是禁用复制的最简单,最清晰的方法:
class X
{
X(X const &) = delete;
void operator=(X const &x) = delete;
};
我不会在问题正文中跟踪你所谈论的虚拟析构函数。听起来你似乎想要一种方法来让你的代码占用较少的源代码字符,但对于任何看到它的人来说都会更加神秘。
如果已删除的功能列表困扰您,您可以将它们隐藏在宏后面,我猜。
#define NON_COPYABLE_NOR_MOVABLE(T) \
T(T const &) = delete; \
void operator=(T const &t) = delete; \
T(T &&) = delete;
答案 2 :(得分:7)
当析构函数被明确默认时,将仅生成复制构造函数和复制赋值运算符。即便如此,他们这一代人也被弃用了。因此,为了拥有虚拟析构函数和所有默认方法,应该编写以下内容:
struct Base
{
Base()=default;
virtual ~Base() = default;
Base(const Base&)=default;
Base& operator=(const Base&)=default;
Base(Base&&)=default;
Base& operator=(Base&&)=default;
};
我肯定会为多个Base
类使用宏。
如果用户定义析构函数,仍会生成2种特殊方法。 禁用已弃用生成复制构造函数和复制赋值运算符有以下几种方法:
删除移动构造函数或移动赋值运算符(不是很明显但非常简短):
Base(Base&&)=delete; // shorter than deleting assignment operator
删除两个复制构造函数和复制赋值运算符:
Base(const Base&)=delete;
Base& operator=(const Base&)=delete;
请注意,如果需要,必须显式声明默认构造函数,例如: Base()=default;
。
宏或继承特殊类也可以用于此目的,但我个人更喜欢删除移动构造函数来实现我自己的宏或基类。使用 Qt 或 boost 时,我更喜欢Q_DISABLE_COPY(Base)
并分别继承boost::noncopyable
,因为它们已经实现,广为人知且可识别。
http://accu.org/index.php/journals/1896 - 这些问题的详细解释和理由。
答案 3 :(得分:1)
您可以通过此操作(Caffe: a fast open framework for deep learning使用该方法):
// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
classname(const classname&);\
classname& operator=(const classname&)
用法示例:
class CNoCopyable{
public:
CNoCopyable(int i):m_d(i){}
private:
int m_d;
// add this line(pass class name)
DISABLE_COPY_AND_ASSIGN(CNoCopyable);
};