C++ Primer 5th notes (chap 13 copy control) move construction and move assignment

1. Move constructor and move assignment operator

Generally speaking, copying a resource will cause some additional overhead. In the case where this copy is not necessary, a class that defines a move constructor and move assignment operator can avoid this problem.
eg.

StrVec::StrVec(StrVec &&s) noexcept //移动操作不应该抛出任何异常elements(s.elemenrs),first_free(s.first_free),cap(s.cap)
{
    
    
	//切断源对象与被移动资源的联系
	s.elements = s.first_free = nullptr;
}

StrVec & strVec::operator=(StrVec &&rhs) noexcept{
    
    
    if(this != &rhs){
    
    
        free()://释放已有元素
        elements = rhs.elments;
        first_free = rhs.first_free;
        cap = rhs.cap;
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}
StrVec v1,v2;
v1 = v2;//v2是左值,使用拷贝赋值运算符
StrVec getVec(istream &);
v2 = getVec(cin);//getVec(cin)是一个右值;使用移动赋值运算符

eg2.

class HasPtr{
    
    
public:
    HasPtr(HasPtr &&p) noexcept:ps(p.ps),i(p.i){
    
    p.ps = 0}

    HasPtr& operator=(HasPtr rhs){
    
    
        swap(*this,rhs);
        return *this;
    }
};

hp = hp2;//hp2 是一个左值;hp2 通过拷贝构造函数来拷贝
hp = std::move(hp2);//移动构造函数来移动hp2

1.1 Exception related

  • noexcept tells the standard library not to throw exceptions to save some extra operations.
  • When vector calls push_back, it may request to reallocate memory for vector. An exception may occur in the process of reallocating memory. Therefore, push_back generally calls the copy constructor. Unless vector knows that the move constructor will not cause an exception.

1.2 The state of the source object after the move

Moving data from an object does not destroy the object, but sometimes it is hoped that the source object will be destroyed after the move operation. After writing a move operation, the state of the source object is:

  • Enter a destructible safe state (the value left in the object is an unknown number)
  • The object is still valid (it can be safely assigned a new value or can be used safely without relying on the current value)

2. Update the Rule of Three and Five

If a class defines any copy operation, it should define all five operations. As mentioned earlier, some classes must define copy constructors, copy assignment operators, and destructors to work correctly. These classes usually have a resource, and copy members must copy this resource.

3. Delete function

The move to operation is generally not implicitly defined as a delete function by the compiler, except in the following situations:

  • Unlike the copy constructor, the move constructor is defined as a delete function if the condition is: a class member defines its own copy constructor and no move constructor, or a class member does not define its own copy constructor and the compiler It also cannot synthesize a move constructor for it. The move assignment operator is similar.
  • If a move constructor or move assignment operator with class members is defined as deleted or inaccessible, then the move constructor or move assignment operator of the class is defined as deleted.
  • Similar to the copy constructor, if the destructor of the class is defined as deleted or inaccessible, the move constructor of the class is defined as deleted.
  • Similar to the copy assignment operator, if the member of the class is const or reference type, the move assignment operator of the class is defined as deleted.

eg.

//假定Y是一个类,他定义了自己的拷贝构造函数,但未定义自己的移动构造函数
struct hasY{
    
    
    hasY() = default;
    hasY(hasY &&) = default;
    Y mem;//hasY将有一个删除的移动构造函数
};

hasY hy,hy2 = std::move(hy);//错误,移动构造函数是删除的

4. Move iterator

make_move_iterator turns an ordinary iterator into a move-to-iterator.

void StrVec::reallocate()
{
    
    
    // we'll allocate space for twice as many elements as the current size
    auto newcapacity = size() ? 2 * size() : 1;

  // allocate new memory
	auto newdata = alloc.allocate(newcapacity);

 // move the data from the old memory to the new
	auto dest= uninitialized_copy(make_move_iterator(begin()),
	make_move_iterator(end()),newdata);
/*
	auto dest = newdata;  // points to the next free position in the new array
       auto elem = elements; // points to the next element in the old array
	for (size_t i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*elem++));
*/
    free();  // free the old space once we've moved the elements

    // update our data structure to point to the new elements
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}

Guess you like

Origin blog.csdn.net/thefist11cc/article/details/113876119