HasPtr class:
#pragma once
#include <iostream>
#include <string>
class HasPtr {
public:
HasPtr(const std::string &s, int a)
: ps(new std::string(s)), i(a) {
std::cout << "Sting with int constructor execute" << std::endl;
}
HasPtr(const std::string &s = std::string())
: ps(new std::string(s)), i(std::stoi(s)) {
std::cout << "String constructor execute" << std::endl;
}
HasPtr(const HasPtr &obj)
: ps(new std::string(*obj.ps)), i(obj.i) {
std::cout << "Copy constructor execute" << std::endl;
}
friend void swap(HasPtr &lhs, HasPtr &rhs) {
std::cout << "HasPtr::swap function execute" << std::endl;
std::swap(lhs.ps, rhs.ps);
std::swap(lhs.i, rhs.i);
}
HasPtr(HasPtr &&s) noexcept : ps(s.ps), i(s.i) { s.ps = nullptr; }
HasPtr & operator=(HasPtr s) {
swap(*this, s);
return *this;
}
~HasPtr() {
delete ps;
}
std::string get_str() const {
return *ps;
}
int get_i() const {
return i;
}
bool operator<(const HasPtr obj) const {
std::cout << "Operator < execute" << std::endl;
return i < obj.i;
}
private:
std::string *ps;
int i;
};
使用移动构造函数为赋值拷贝带来了好处:
复制拷贝运算符的形参不是引用,需要使用拷贝构造函数来传递。如果等号右边的对象是右值,则会使用移动构造函数,将原对象的指针设为空。赋值操作符只需要swap即可,无需指定析构。右值对象出作用域时会自行析构。
main.cpp
int main()
{
HasPtr a("1"), b("2");
a = std::move(b);
return 0;
}
执行过程:
通过两个string构造两个HasPtr对象。a调用复制拷贝运算符,以b为实参通过移动构造函数构造形参。
调用swap函数交换指针。
析构所有对象
值得一提的是:对空指针调用delete运算符不会产生错误(析构函数会析构那个被move过的原对象,其指针已经被置为空)。delete运算符会检查指针是否为空。