std::unordered_set::emplace
#include <unordered_set>
template <class... Args>
pair<iterator, bool> emplace(Args&&... args);
Xây dựng (construct) một phần tử mới trực tiếp trong std::unordered_set, tránh việc sao chép hoặc di chuyển không cần thiết.
Tham số
args
- Danh sách các đối số (có thể trống) được sử dụng để khởi tạo phần tử mới. Các đối số này sẽ được truyền đến constructor của kiểu phần tử
value_type
của std::unordered_set.
Giá trị trả về
std::pair<iterator, bool>
iterator
: Một iterator trỏ đến phần tử vừa được chèn (nếu chèn thành công) hoặc phần tử đã tồn tại có giá trị tương đương (nếu chèn thất bại).bool
: true nếu phần tử được chèn thành công (phần tử mới), false nếu phần tử đã tồn tại (chèn thất bại).
Đặc điểm
- Xây dựng phần tử tại chỗ (In-place construction):
emplace()
tạo phần tử mới trực tiếp trong bộ nhớ của std::unordered_set, tránh việc tạo ra các đối tượng tạm thời không cần thiết, tối ưu hiệu suất. - Tránh sao chép và di chuyển: Bằng cách xây dựng phần tử tại chỗ,
emplace()
giúp tránh việc sao chép (copy) hoặc di chuyển (move) các đối tượng, đặc biệt hiệu quả khi làm việc với các đối tượng lớn hoặc phức tạp. - Hỗ trợ variadic template:
emplace()
sử dụng variadic template (Args&&... args), cho phép nó nhận số lượng đối số tùy ý, phù hợp với constructor của kiểu phần tử. - Có thể làm thay đổi iterator: Việc chèn phần tử vào std::unordered_set có thể làm thay đổi (invalidate) các iterator đang trỏ đến các phần tử trong std::unordered_set.
- Phân biệt với
insert()
:insert()
sẽ tạo bản sao hoặc di chuyển phần tử được truyền vào trong khi đóemplace()
sẽ xây dựng phần tử tại chỗ trong std::unordered_set, cho phép dùngemplace()
ngay cả khi kiểu phần tử không hỗ trợ copy/move constructor. - Có thể ném ngoại lệ: Nếu việc cấp phát bộ nhớ cho phần tử mới thất bại,
emplace()
có thể ném ra ngoại lệ std::bad_alloc. Ngoài ra, nếu constructor củavalue_type
ném ngoại lệ,emplace()
cũng sẽ ném ngoại lệ. - Phần tử duy nhất: std::unordered_set chỉ lưu trữ các phần tử duy nhất. Nếu bạn cố gắng chèn một phần tử đã tồn tại,
emplace()
sẽ không chèn thêm phần tử mới và second của pair trả về sẽ là false. - Độ phức tạp: Độ phức tạp trung bình của
emplace()
làO(1)
, trường hợp xấu nhất làO(n)
, với n là số phần tử trong std::unordered_set.
Ví dụ
#include <iostream>
#include <unordered_set>
#include <string>
int main() {
std::unordered_set<std::string> myset;
// Chèn một phần tử mới vào unordered_set, sử dụng emplace()
auto ret = myset.emplace("apple");
// Kiểm tra xem phần tử đã được chèn thành công hay chưa
if (ret.second) {
std::cout << "Element 'apple' inserted successfully.\n";
std::cout << "Iterator points to: " << *ret.first << '\n';
}
// Thử chèn một phần tử đã tồn tại
auto ret2 = myset.emplace("apple");
if (!ret2.second) {
std::cout << "Insertion of 'apple' failed (element already exists).\n";
std::cout << "Iterator points to: " << *ret2.first << '\n';
}
// Chèn thêm các phần tử khác
myset.emplace("banana");
myset.emplace("orange");
// In ra các phần tử trong unordered_set
std::cout << "myset:";
for (const auto& str : myset) {
std::cout << " " << str;
}
std::cout << '\n'; // Output: myset: orange banana apple (thứ tự có thể khác)
return 0;
}
Với class không hỗ trợ copy/move constructor
#include <iostream>
#include <unordered_set>
class NonCopyable {
public:
NonCopyable(int val) : data(val) {}
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
// Move constructor/assignment are not necessary but good practice
NonCopyable(NonCopyable&&) = default;
NonCopyable& operator=(NonCopyable&&) = default;
int data;
// Cần định nghĩa toán tử == và hàm băm (std::hash) để sử dụng trong unordered_set
bool operator==(const NonCopyable& other) const {
return data == other.data;
}
};
namespace std {
template <>
struct hash<NonCopyable> {
std::size_t operator()(const NonCopyable& obj) const {
return std::hash<int>()(obj.data);
}
};
}
int main() {
std::unordered_set<NonCopyable> myset;
// myset.insert(NonCopyable(10)); // Error: Copy constructor is deleted
myset.emplace(10); // OK: Constructs the element in-place
myset.emplace(20); // OK: Constructs the element in-place
return 0;
}
Các hàm liên quan
insert | Chèn một hoặc nhiều phần tử mới vào std::unordered_set |
find | Tìm kiếm một phần tử có giá trị bằng với giá trị cho trước trong std::unordered_set |