明确拒绝编译器的好意。

阅读: 评论:0

明确拒绝编译器的好意。

明确拒绝编译器的好意。

——effective c++ item 6 & item 5

编译器的好意

编译器会为一个没有默认构造函数,复制构造函数,复制操作运算符的类创建它们。但是编译器创建的复制构造函数和复制操作运算符,只是单纯地将来源对象的每一个非静态成员变量拷贝到目标对象。

但是编译器还不是每次都会添加复制构造函数和赋值运算操作符。。例如

// 不能通过编译
template<class T>
class Name_obj {
private:std::string &name_value;const T obj_value;
public:Name_obj(std::string &name, const T &value): name_value(name),obj_value(value){ }// 没有声明和实现任何的复制构造函数和复制操作运算符,希望编译器会提供
};

然后用这个类写出了如下调用

std::string new_obj("foo");
std::string old_obj("grand foo");
Name_obj<int> f(new_obj, 233);
Name_obj<int> g(old_obj, 666);
f = g;      // 罪恶之源。。

赋值之前f.name_valueg.name_value都会指向各自的string对象。执行到赋值的一步操作时,c++表示“不能让引用改为指向不同的对象”。
面对这个难题,编译器选择拒绝编译那一步操作。如果你打算在一个”内含 引用 成员“的类中支持赋值操作,你必须自己定义赋值操作运算符。对于”内含const 成员“的类中,编译器的反应也是一样的。
所以编译时抛出错误:使用了被删除的函数‘ Name_obj& Name_obj::operator=(const Name_obj&) ’。

因此我们还是不要让编译器自动生成代码了。。

如何拒绝编译器

如果你并不想要你的类支持赋值和复制。就像标准io库(iostream)里的ios_base, basic_ios,和sentry一样不支持复制行为。

编译器为你声明的方法都是public的,因此你只需要将你的方法声明为private。

class Foo {
public:private:Foo(const Foo &);Foo & operator=(const Foo &);
};

借由明确声明一个成员函数,你成功的阻止编译器暗自创建自己的版本。而且防止了别人错误的调用了它。
不过,友元函数可以调用类里面的私有方法。幸运的是,如果不慎使用友元函数调用了它,连接器会发出抱怨。其实我们可以把链接期错误移到编译器,而且这是件好事。(毕竟你不希望编译大半天,没有错误,最后连接出现错误)。

所以我们可以设计一个类专门阻止赋值和复制操作。其他类需要禁止这类操作的时候直接继承就好了。

class Uncopyable_base {
protected:Uncopyable_base() {}~Uncopyable_base() {}
private:Uncopyable_base(const Uncopyable_base &);Uncopyable_base & operator=(const Uncopyable_base &);
};// 使用的时候继承一下
class Foo : private Uncopyable_base {};

boost 已经为你准备好了

boost 下有个noncopyable。可以直接使用

#include <boost/noncopyable.hpp>
class Foo : private boost::noncopyable
{};

本文发布于:2024-01-29 17:44:46,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170652148917182.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:编译器   好意
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23