Notas 5 do C ++ Primer (capítulo 13, controle de cópia) mover a construção e mover a atribuição

1. Mova o construtor e mova o operador de atribuição

De um modo geral, copiar um recurso causará alguma sobrecarga adicional. No caso em que essa cópia não é necessária, uma classe que define um construtor de movimento e um operador de atribuição de movimento pode evitar esse problema.
por exemplo.

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 Exceção relacionada

  • noexcept diz à biblioteca padrão para não lançar exceções para salvar algumas operações extras.
  • Quando o vetor chama push_back, ele pode solicitar a realocação de memória para o vetor. Uma exceção pode ocorrer no processo de realocação de memória. Portanto, push_back geralmente chama o construtor de cópia. A menos que vetor saiba que o construtor de movimento não causará uma exceção.

1.2 O estado do objeto de origem após a movimentação

Mover dados de um objeto não destrói o objeto, mas às vezes espera-se que o objeto de origem seja destruído após a operação de movimentação. Depois de escrever uma operação de movimentação, o estado do objeto de origem é:

  • Entre em um estado de segurança destrutível (o valor deixado no objeto é um número desconhecido)
  • O objeto ainda é válido (pode ser atribuído com segurança um novo valor ou pode ser usado com segurança sem depender do valor atual)

2. Atualize a regra de três e cinco

Se uma classe define qualquer operação de cópia, ela deve definir todas as cinco operações. Conforme mencionado anteriormente, algumas classes devem definir construtores de cópia, operadores de atribuição de cópia e destruidores para funcionarem corretamente. Essas classes geralmente têm um recurso e os membros da cópia devem copiar esse recurso.

3. Excluir função

A operação mover para geralmente não é definida implicitamente como uma função de exclusão pelo compilador, exceto nas seguintes situações:

  • Ao contrário do construtor de cópia, o construtor de movimento é definido como uma função de exclusão se a condição for: um membro da classe define seu próprio construtor de cópia e nenhum construtor de movimento, ou um membro da classe não define seu próprio construtor de cópia e o compilador Ele também não pode sintetizar um construtor de movimento para ele. O operador de atribuição de movimentação é semelhante.
  • Se um construtor de movimentação ou operador de atribuição de movimentação com membros da classe for definido como excluído ou inacessível, o construtor de movimentação ou operador de atribuição de movimentação da classe será definido como excluído.
  • Semelhante ao construtor de cópia, se o destruidor da classe for definido como excluído ou inacessível, o construtor de movimentação da classe será definido como excluído.
  • Semelhante ao operador de atribuição de cópia, se o membro da classe for const ou tipo de referência, o operador de atribuição de movimentação da classe é definido como excluído.

por exemplo.

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

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

4. Mova o iterador

make_move_iterator transforma um iterador comum em um 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;
}

Acho que você gosta

Origin blog.csdn.net/thefist11cc/article/details/113876119
Recomendado
Clasificación