Eu tenho uma std::vector
série de objetos de uma certa classe A
. A classe não é trivial e tem construtores de cópia e construtores de movimento definidos.
std::vector<A> myvec;
Se eu preencher o vetor com A
objetos (usando por exemplo myvec.push_back(a)
), o vetor aumentará de tamanho, usando o construtor de cópia A( const A&)
para instanciar novas cópias dos elementos no vetor.
Posso de alguma forma impor que o construtor de movimento da classe A
está começando a ser usado em vez disso?
Respostas:
Você precisa informar ao C ++ (especificamente
std::vector
) que o seu construtor e destruidor de movimento não atira, usandonoexcept
. Então, o construtor de movimento será chamado quando o vetor crescer.Esta é a forma de declarar e implementar um construtor de movimento que é respeitado por
std::vector
:Se o construtor não for
noexcept
, nãostd::vector
pode usá-lo, pois então não pode garantir as garantias de exceção exigidas pelo padrão.Para mais informações sobre o que é dito no padrão, leia C ++ Move semantics and Exceptions
Crédito para Bo, que deu a entender que pode ter a ver com exceções. Considere também o conselho de Kerrek SB e use
emplace_back
quando possível. Ele pode ser mais rápido (mas muitas vezes não é), pode ser mais clara e mais compacto, mas também existem algumas armadilhas (especialmente com construtores não explícitas).Edite , muitas vezes o padrão é o que você deseja: mova tudo o que pode ser movido, copie o resto. Para pedir isso explicitamente, escreva
Fazendo isso, você obterá noexcept quando possível: O construtor Move padrão está definido como noexcept?
Observe que as versões anteriores do Visual Studio 2015 e anteriores não davam suporte a isso, embora ofereça suporte à semântica de movimentação.
fonte
value_type
's ctor movimento énoexcept
? Talvez a linguagem restrinja o conjunto de candidatos de chamada de função quando o escopo de chamada também é umanoexcept
função?noexcept
construtor de movimento.is_nothrow_move_constructible
será verdadeiro se houver umnothrow
construtor de cópia. Não tenho conhecimento de nenhum caso real denothrow
construtores de cópias caros, então não está claro se isso realmente importa.noexcept
no cabeçalho e na implementação e, quando faço um push_back (std:; move), ele ainda chama o construtor de cópia. Estou arrancando meu cabelo aqui.std::move()
apush_back()
chamada errada . Uma daquelas vezes em que você está procurando tanto por um problema que não vê o erro óbvio bem na sua frente. E então era hora do almoço e esqueci de deletar meu comentário.Curiosamente, o vetor do gcc 4.7.2 só usa o construtor de movimento se o construtor de movimento e o destruidor o forem
noexcept
. Um exemplo simples:Isso produz o esperado:
No entanto, quando removo
noexcept
de~foo()
, o resultado é diferente:Eu acho que isso também responde a essa pergunta .
fonte
Parece que a única maneira (para C ++ 17 e anteriores) de forçar o
std::vector
uso da semântica de movimentação na realocação é excluindo o construtor de cópia :). Desta forma, ele usará seus construtores de movimento ou teste de dados, em tempo de compilação :).Existem muitas regras onde
std::vector
NÃO DEVE usar o construtor de movimento na realocação, mas nada sobre onde ele DEVE USAR .Viver
ou
Código ao vivo
Sua
T
classe deve ternoexcept
o construtor de movimento / operador de atribuição enoexcept
destruidor. Caso contrário, você obterá um erro de compilação.fonte