Ответ
Да, можно, но только если тип элемента вектора (T) имеет конструктор по умолчанию.
Вызов vec.emplace_back(); эквивалентен созданию элемента с помощью T() и его размещению в конце вектора. Это работает благодаря perfect forwarding и вызову конструктора T с пустым списком аргументов.
Пример:
#include <vector>
#include <string>
int main() {
std::vector<std::string> words;
words.emplace_back(); // Создает пустую строку, вызывая std::string().
// words теперь содержит: [""]
std::vector<int> numbers;
numbers.emplace_back(); // Создает int, инициализированный нулем (int()).
// numbers теперь содержит: [0]
}
Что произойдет, если конструктора по умолчанию нет? Компиляция завершится ошибкой.
struct Point {
int x, y;
Point(int x, int y) : x(x), y(y) {} // Пользовательский конструктор
// Конструктор по умолчанию Point() = default; не сгенерирован
};
std::vector<Point> points;
points.emplace_back(); // ОШИБКА КОМПИЛЯЦИИ:
// Нет подходящего конструктора для вызова 'Point::Point()'
Сравнение с push_back:
vec.push_back(T()); // Требует создания временного объекта, затем его перемещения/копирования.
vec.emplace_back(); // Создает объект напрямую в памяти вектора, избегая лишних операций.
Вывод: emplace_back() без аргументов — это эффективный способ добавить в вектор элемент, инициализированный значением по умолчанию, при условии, что такой конструктор существует.
Ответ 18+ 🔞
А, ну это же классика, ебать мои старые костыли! Смотри, тут всё просто, как три копейки.
Да, конечно, можно. Но с одной оговоркой, ёпта. Твой тип T внутри вектора должен уметь рождаться просто так, из ниоткуда, то есть иметь конструктор по умолчанию. Без этого — пиши пропало.
Когда ты пишешь vec.emplace_back();, это всё равно что крикнуть: «Эй, вектор, приготовь местечко на своём диванчике в конце и прямо там, на месте, роди мне новый T с помощью T()!». Вся магия в этом perfect forwarding, который передаёт пустой список аргументов прямо в конструктор.
Вот, смотри, как это выглядит вживую:
#include <vector>
#include <string>
int main() {
std::vector<std::string> words;
words.emplace_back(); // Просто вызывает std::string() и вуаля — пустая строка на месте.
// Теперь в words болтается одна пустая строка: [""]
std::vector<int> numbers;
numbers.emplace_back(); // Вызывает int(), что даёт нам нолик.
// numbers теперь: [0]
}
А что будет, если конструктора по умолчанию нет? Да хуй с горы — компилятор тебе такую ошибку влепит, что мало не покажется.
struct Point {
int x, y;
Point(int x, int y) : x(x), y(y) {} // Конструктор свой есть, а по умолчанию — нихуя.
// Point() = default; — этой строчки нет, поэтому дефолтного рождения не будет.
};
std::vector<Point> points;
points.emplace_back(); // ОШИБКА, БЛЯДЬ!
// Компилятор орет: "Чел, я не знаю, как создать Point()! Где аргументы, мать твою?"
И главное, чем это лучше старого доброго push_back:
vec.push_back(T()); // Сначала создаёшь сироту-времянку где-то сбоку (T()), потом её толкаешь в вектор, заставляя копироваться или перемещаться. Лишняя работа.
vec.emplace_back(); // А это как по волшебству: память в векторе выделилась — и сразу в ней объект родился. Никаких лишних телодвижений. Красота!
Короче, вывод: emplace_back() без аргументов — это хитрая, но эффективная фишка, чтобы воткнуть в конец вектора элемент «с нуля». Работает на ура, если тип это позволяет. Если нет — ну, извини, придётся аргументы передавать.