Middle
O que acontece com os elementos de std::vector durante a operação realloc?
sobes.tech IA
Resposta da IA
O std::vector não usa realloc. Quando se altera o tamanho do contêiner, exigindo uma redistribuição de memória, o seguinte acontece:
- Uma nova área de memória de tamanho suficiente é alocada.
- Os elementos da antiga área são movidos para a nova.
- Para tipos que suportam semântica de movimento (
Tcom um construtor de movimento e/ou operador de atribuição de movimento corretamente implementados), é usado o movimento. Isso é mais eficiente, pois os recursos antigos (por exemplo, memória alocada dentro dos objetos) são transferidos para os novos objetos, e os antigos permanecem em um estado válido, mas indefinido ou são limpos pelos destruidores. - Para tipos que não suportam semântica de movimento ou se o compilador não consegue aplicar o movimento, é usada cópia.
- Se os elementos forem triviais de copiar (
Té um tipo POD ou possui operações triviais de cópia e movimento), pode-se usarmemcpyou funções similares de baixo nível para copiar rapidamente os dados brutos.
- Para tipos que suportam semântica de movimento (
- Os destruidores são chamados para os elementos na antiga área de memória.
- A antiga área de memória é liberada.
É importante notar que os ponteiros e referências aos elementos na antiga área tornam-se inválidos após a redistribuição.
#include <vector>
#include <iostream>
#include <string>
struct MyItem {
std::string name;
// Construtor
MyItem(const std::string& n) : name(n) {
std::cout << "Constructing " << name << std::endl;
}
// Construtor de cópia
MyItem(const MyItem& other) : name(other.name) {
std::cout << "Copying " << name << std::endl;
}
// Operador de atribuição por cópia
MyItem& operator=(const MyItem& other) {
if (this != &other) {
name = other.name;
std::cout << "Copy assigning " << name << std::endl;
}
return *this;
}
// Construtor de movimento
MyItem(MyItem&& other) noexcept : name(std::move(other.name)) {
std::cout << "Moving " << name << std::endl;
}
// Operador de atribuição por movimento
MyItem& operator=(MyItem&& other) noexcept {
if (this != &other) {
name = std::move(other.name);
std::cout << "Move assigning " << name << std::endl;
}
return *this;
}
// Destruidor
~MyItem() {
std::cout << "Destroying " << name << std::endl;
}
};
int main() {
std::vector<MyItem> items;
items.reserve(2); // Reservar espaço para 2 elementos
items.emplace_back("item1"); // Sem realloc
items.emplace_back("item2"); // Sem realloc
std::cout << "Adding third item, triggering realloc-like operation:" << std::endl;
items.emplace_back("item3"); // Requer realloc
// A saída mostrará o movimento para item1 e item2, depois a destruição dos objetos antigos
// e a construção do novo item3.
// Se MyItem não suportasse movimento, haveria uma cópia.
return 0;
}