一个关于C++移动构造函数问题

Zelda256 2016-09-26 01:25:59
C++primer书上的例子 StrVec 是一个仿vector<string>的类

其中移动赋值运算符为:
StrVec &StrVec::operator=(StrVec &&rhs) noexcept
{
if(this!=&rhs){ //检测是否是字符值
free();
elements = rhs.elements; //elements是一个指向第一个元素的指针
first_free = rhs.first_free; //first_free是指向第一个未使用的空间
cap = rhs.cap; //cap是尾后指针
rhs.elements = rhs.first_free = rhs.cap = nullptr; //使其实可析构的
}
return *this;
}
在上面代码中,传入的实参是一个rvalue,后面的交换资源管理 也是移动也就是说
elements = rhs.elements; 指的是移动,elements窃取了rhs.elements的资源。
下面是另一个例子 Message的一个类
Message &Message::operator=(Message &&rhs)
{
if(this!=&rhs){ //检查自赋值
remove_from_Folders();
contents = std::move(rhs.contents); //移动赋值操作 contents是一个string
move_Folders(&rhs); //重置Floders指向本Message
}
return *this;
}
我的问题是 :在Message中rhs也是一个rvalue,然后下面的接管资源的时候为什么要是:contents = std::move(rhs.contents);
而不直接是contents = rhs.contents; 。还是说加上std::move是为了显示的说明要调用移动赋值运算符?还是说StrVec中
elements = rhs.elements;只是拷贝了指针???
贴上C++Primer上的这两个类的完整成员:
class StrVec{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}//默认构造函数
StrVec(initializer_list<string>);
StrVec(const StrVec &); //拷贝构造函数
StrVec &operator=(const StrVec &); //拷贝赋值运算符
StrVec(StrVec &&); //移动构造函数
StrVec &operator=(StrVec &&); //移动赋值运算符
~StrVec(); //析构函数

void push_back(const string &); //拷贝元素
void push_back(string &&); //移动元素
size_t size() const {return first_free-elements;}
size_t capacity() const {return cap-elements;}
string *begin()const{return elements;}
string *end()const{return first_free;}
StrVec &reserve(size_t n); //分配大小为n空间
StrVec &resize(size_t n); //重置空间大小为n

private:
string *elements; //指向起始元素
string *first_free; //第一个非实际元素
string *cap; //指向尾后位置的指针

//static allocator<string> alloc; //分配元素
void chk_n_alloc(){if(size()==capacity()) reallocate();} //检查空间是否够大
pair<string*,string*> alloc_n_copy(const string*,const string*);
void free(); //销毁元素并释放内存
void reallocate(); //获得更多内存并拷贝已有元素
void reallocate();
};



class Message{
public:
friend class Floder;
friend void swap(Message &lhs,Message &rhs);
explicit Message(const string &str = ""):contents(str) { }
//拷贝控制成员
Message(const Message &);
Message &operator=(const Message &);
Message(Message &&); //移动构造函数
Message &operator=(Message &&); //移动赋值运算符
~Message();
//从给定Folder添加/删除本Message
void save(Folder&);
void remove(Folder&);
private:
string contents;
set<Folder*> folders;
//拷贝构造函数,拷贝赋值运算符合析构函数所使用的工具函数
void add_to_Folders(const Message &);//将本message添加到指向参数的Folder中
void remove_from_Folders();//从folder中每个Folder中删除本Message

void addFldr(Folder* f){folders.insert(f);}
void remFldr(Folder* f){folders.erase(f);}
void move_Folders(Message *m);
};
...全文
179 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
baidu_36583949 2016-11-01
  • 打赏
  • 举报
回复
rhs是一个右值引用,但它是一个左值,右值是要被销毁的对象或字面值常量之类的,所以要用move函数,使其成为右值, contents = std::move(rhs.contents),因为string有移动复制运算符,所以它调用了移动复制运算符移动元素,而第一个例子StrVec中只是简单地拷贝元素,所以不需要用右值。
fefe82 2016-09-26
  • 打赏
  • 举报
回复
引用 3 楼 Vit_rose 的回复:
引用 2 楼 lianshaohua 的回复:
你的问题是?
就是 为什么Message 中的那句要写成 contents = std::move(rhs.contents); 而不直接是contents = rhs.contents;rhs是一个右值 rhs.contents不是右值吗????第一个例子StrVec就是没写std::move
rhs 的类型是一个右值引用,但作为一个表达式,其结果不是一个右值。 左值与右值是用来描述表达式的结果的,不是用来描述类型的,也不是用于描述对象的。 右值引用作为一个类型,仅表示它可以绑定到一个返回右值的表达式的结果。
paschen 版主 2016-09-26
  • 打赏
  • 举报
回复
函数参数中的Message &&rhs 本身(类型)是一个左值
Zelda256 2016-09-26
  • 打赏
  • 举报
回复 1
引用 2 楼 lianshaohua 的回复:
你的问题是?
就是 为什么Message 中的那句要写成 contents = std::move(rhs.contents); 而不直接是contents = rhs.contents;rhs是一个右值 rhs.contents不是右值吗????第一个例子StrVec就是没写std::move
ztenv 版主 2016-09-26
  • 打赏
  • 举报
回复
你的问题是?
Zelda256 2016-09-26
  • 打赏
  • 举报
回复
求大神、、、、、

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧