Se alguém copia um std::vector
em outro, ou copia elementos de um std::vector
em um bloco maior ( reserve
) ou menor ( shrink_to_fit
) da memória heap, qual construtor do tipo do elemento é chamado?
No programa de exemplo:
#include <vector>
#include <iostream>
struct A {
A() {}
A(A&) { std::cout << "A(A&) "; }
A(const A&) { std::cout << "A(const A&) "; }
};
int main() {
std::vector<A> v(1);
v.reserve(10);
auto w = v;
v.shrink_to_fit();
}
Eu esperaria ver A(const A&) A(const A&) A(const A&)
uma saída. Mas, na realidade, as implementações da biblioteca padrão divergem:
libc++
impressõesA(const A&) A(A&) A(const A&)
,libstdc++
impressõesA(const A&) A(const A&) A(A&)
,- e o Microsoft STL imprime
A(A&) A(A&) A(A&)
.
Demonstração online: https://gcc.godbolt.org/z/TTqxv9sd3
É correto supor que se o construtor de not- const
lvalue for chamado, o código do usuário terá permissão para modificar seu argumento (pelo menos temporariamente)?
Não vejo razão para que a biblioteca seja obrigada a garantir que a
const
sobrecarga seja usada.O construtor de cópia do contêiner requer, conforme [container.reqmts]/12, que o tipo de elemento seja CopyInsertable de um lvalue
v
do seu tipo para o contêiner, independentemente daconst
qualificação - dev
. Ele também requer a pós-condição ( [container.alloc.reqmts]/2.4 ):o que implica que se o
const
construtor não-cópia for usado, então não deve resultar no valor do objeto original sendo diferente após a chamada, pelo menos.Para mim, é um pouco menos claro se a modificação do argumento é completamente proibida, pois isso é declarado apenas como pós-condição. Suspeito, porém, que essa seja a intenção.