文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>常见错误56: 直接和复制初始化----读书笔记《c++ gotchas》...

常见错误56: 直接和复制初始化----读书笔记《c++ gotchas》...

时间:2010-08-19  来源:lzueclipse

在作者工作的那个年代(15年前了,那时没准你还读小学),丑陋的初始化比比皆是。

class Y {

public:

    Y(int);

    ~Y();

};

对于Y对象,有三种初始化过程:

Y a(1066);

Y b = Y(1066);

Y c = 1066;

a是直接初始化,调用Y::Y(int)。

b和c都是复制初始化。

b初始化过程是首先生成一个匿名临时对象,然后复制构造完成初始化,然后匿名临时

对象析构,类似于以下伪代码:

Y temp(1066);

Y b(temp);

temp.~Y();

c初始化过程和b完全一样,只不过产生匿名临时对象的要求不那么显著罢了。

对Y做些改动:

class Y {

public:

    Y(int);

    Y(const Y &)

    {

        abort();

    }

~Y();

};

显然,Y对象对于任何复制构造函数都没有容忍度。

为什么我们编译和运行上面三个初始化语句的时间,并未引起进程终止(abort未被调用),这说明了什么?

标准允许编译器执行某种代码变换,去除这个临时对象的初始化合复制构造函数的调用,产生和

直接初始化一模一样的目标码。这是一种优化,大部分编译器都会这么做,但标准没有强制要求这么做,

所以存在不确定性。

还是采用直接初始化最好:

Y a(1066), b(1066), c(1066);

如果你脾气很倔,想实现不做代码变换(优化)时的复制初始化语义:

struct {

    char b_[sizeof(Y)];

}aY;//准备一个和Y具有相同尺寸的存储块

new (&aY) Y(1066);//用placement new创建一个中间对象

Y d(reinterpret_cast (aY) );//复制构造

reterpret_cast (aY).~Y();//析构

这个也太费心了,算了吧。

下面理解下在代码变换中的一个要点:

编译器在校验过原始代码的语义后才实施这个变换,如果未经变换的初始化根本就是错的,

那么编译器会报错,不做变换。

class X {

public:

    X(int);

    ~X();

    //…

private:

    X(const X &);

};

X a(1066);//正确

X b = 1066;//错误,copy构造为private

X c = X(1066);//错误,copy构造为private

直接和复制初始化对非class对象也起作用,不过结果是可预期的:

int i(12);//直接初始化

int j = 12;//复制初始化,结果相同

对于这种类型,就选看起来顺眼的就好。

在模板内,还是使用直接初始化比较好,因为那里变量的类型在具现之前都是未知的。

以下例子,形参In是迭代器类型,形参N是计数器类型,seqLength是一个简化了的计算序列长度的泛

型算法:

template

void seqLength(N &len, In b, In e) {

    N n(0);//要这样写,不要写成N n = 0;

    while( b != e) {

        ++n;

        ++b;

    }

    len = n;

}

对N进行了直接初始化,使得我们能够处理自定义的、禁止进行复制构造的数值类型。

一句话,尽量使用直接初始化。

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载