您的位置:首页 > 编程语言 > C语言/C++

c++ 11学习笔记--右值引用和移动构造语义

2014-07-22 14:14 477 查看
今天我决定尝试用另外一种方式来表达,任何新语法的的产生都是为了解决某个问题,所以今天先看问题。

class myStr
{
protected:
char* str_;

public:
myStr(void)                       // 默认的构造函数,什么也不做
: str_(nullptr)
{}

myStr(const char* rhs)            // 普通赋值构造函数
: str_(nullptr)
{
if (!rhs) return;
str_ = new char[1024];
strcpy(str_, rhs);
//  cout << "Str constructor " << str_ << std::endl;
}

myStr(const myStr& rhs)             // 拷贝构造函数
: str_(nullptr)
{
if (!rhs) return;
str_ = new char[1024];
strcpy(str_, rhs.str_);
//  cout << "Str copy constructor " << str_ << std::endl;
}

myStr(myStr&& rhs)
: str_(nullptr)
{
swap(rhs);
//  std::cout << "Str move constructor " << str_ << std::endl;
}

~myStr()                          // 析构函数
{
if (!str_) return;
//  std::cout << "Str destructor " << str_ << std::endl;
delete [] str_;
}

const myStr& operator=(myStr rhs)   // 赋值操作符重载
{
rhs.swap(*this);            // 使用copy-and-swap惯用法获得数据
return (*this);             // 避免重复撰写operator=
}

void swap(myStr& rhs)             // 交换算法
{
std::swap(str_, rhs.str_);
}

operator char*(void) const
{
return str_;
}

myStr& operator+=(const char* rhs)
{
if (rhs) strcat(str_, rhs);
return (*this);
}

//    friend myStr operator+(const myStr& x, const myStr& y)
//    {
//        return myStr(x) += y;
//    }
friend myStr operator+(const myStr& x, const myStr& y)
{
return std::move(myStr(x) += y);
}


执行下面的代码

myStr ss("000");
myStr s1("11111"), s2("22222"), s3("3333333"), s4("4444444");
cout << std::endl;
time_t timestamp1;
time_t timestamp2;
time_t timestamp3;

const long long max = 30000000;
time(×tamp1);

for (long long i = 0; i<max; i++) {
ss = s1 + s2 + s3 + s4;
}
time(×tamp2);

timestamp3 = timestamp2 - timestamp1;


下面的代码是唯一不同的实现,但是却带来30-40%的性能差距。

/    friend myStr operator+(const myStr& x, const myStr& y)
//    {
//        return myStr(x) += y;
//    }
friend myStr operator+(const myStr& x, const myStr& y)
{
return std::move(myStr(x) += y);
}


再找一个例子

class MemoryBlock
{
public:

// 构造器(初始化资源)
explicit MemoryBlock(size_t length)
: _length(length)
, _data(new int[length])
{
std::cout << "MemoryBlock constructor "  << std::endl;
}

// 析构器(释放资源)
~MemoryBlock()
{
if (_data != nullptr)
{
delete[] _data;
}
std::cout << "MemoryBlock destructor "  << std::endl;
}

// 拷贝构造器(实现拷贝语义:拷贝that)
MemoryBlock(const MemoryBlock& that)
// 拷贝that对象所拥有的资源
: _length(that._length)
, _data(new int[that._length])
{
std::copy(that._data, that._data + _length, _data);
std::cout << "copy constructor "  << std::endl;
}

// 拷贝赋值运算符(实现拷贝语义:释放this + 拷贝that)
MemoryBlock& operator=(const MemoryBlock& that)
{
if (this != &that)
{
// 释放自身的资源
delete[] _data;

// 拷贝that对象所拥有的资源
_length = that._length;
_data = new int[_length];
std::copy(that._data, that._data + _length, _data);
}
return *this;
}

// 移动构造器(实现移动语义:移动that)
MemoryBlock(MemoryBlock&& that)
// 将自身的资源指针指向that对象所拥有的资源
: _length(that._length)
, _data(that._data)
{
// 将that对象原本指向该资源的指针设为空值
that._data = nullptr;
that._length = 0;
}

// 移动赋值运算符(实现移动语义:释放this + 移动that)
MemoryBlock& operator=(MemoryBlock&& that)
{
if (this != &that)
{
// 释放自身的资源
delete[] _data;

// 将自身的资源指针指向that对象所拥有的资源
_data = that._data;
_length = that._length;

// 将that对象原本指向该资源的指针设为空值
that._data = nullptr;
that._length = 0;
}
return *this;
}
private:
size_t _length; // 资源的长度
int* _data; // 指向资源的指针,代表资源本身
};

MemoryBlock f() { return MemoryBlock(50); }


执行下面的代码

const long long max = 100000;
time_t timestamp1;
time_t timestamp2;
time_t timestamp3;

time(×tamp1);
for (long long i = 0; i<max; i++)
{
MemoryBlock a = MemoryBlock(50);

MemoryBlock c = std::move(a);
}

time(×tamp2);
timestamp3 = timestamp2 - timestamp1;


如果把MemoryBlock c = std::move(a)换成MemoryBlock c = a;

性能上大概也有30%的差距。

这就是右值引用和移动构造语义带来的好处,我理解就是以前只能引用左值,而右值是不能引用的,新语法的加入实现了右值的引用,减少了零时对象的产生销毁,但是也带来了更多怪异的语法,明显增加了c++的学习成本,如果语法设计角度,像oc一样增加类似引用计数器来管理对象,会不会更加优雅一下,至少让上层的码农不会那么累,其实通智能指针也能达到同样的效果。

这么多年了c++都在做加法,让学习,使用成本太高了,标准委员为的大爷些什么时候考虑一下做点减法呢,不要让c++那么学院派或者满地都是陷阱,也不要让实现一种技术有10种方法,但是有5种都是陷阱。靠!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: