Chuyển tới nội dung chính

std::multiset::emplace

#include <set>

template <class... Args>
iterator emplace(Args&&... args);

Xây dựng (construct) một phần tử mới trực tiếp trong std::multiset tại vị trí thích hợp, tránh việc sao chép hoặc di chuyển không cần thiết. std::multiset sẽ tự động sắp xếp phần tử mới được chèn vào đúng vị trí để duy trì thứ tự đã sắp xếp của các phần tử trong multiset.

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::multiset.

Giá trị trả về

  • Trả về một iterator trỏ đến phần tử vừa mới được chèn vào.

Đặc điểm

  1. 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::multiset, 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.
  2. 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.
  3. 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ử.
  4. Có thể làm thay đổi iterator: Việc chèn phần tử vào std::multiset có thể làm thay đổi (invalidate) các iterator đang trỏ đến các phần tử trong std::multiset.
  5. 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::multiset, cho phép dùng emplace() ngay cả khi kiểu phần tử không hỗ trợ copy/move constructor.
  6. 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ủa value_type ném ngoại lệ, emplace() cũng sẽ ném ngoại lệ.
  7. Chèn phần tử trùng lặp: Không giống như std::set, std::multiset cho phép chèn các phần tử trùng lặp, do đó emplace() luôn chèn thành công và trả về iterator trỏ đến phần tử mới được chèn.
  8. Độ phức tạp: Độ phức tạp của emplace()O(log n), với n là số phần tử trong std::multiset.

Ví dụ

#include <iostream>
#include <set>
#include <string>

int main() {
std::multiset<std::pair<int, std::string>> mymultiset;

// Chèn một phần tử mới vào multiset, sử dụng emplace()
auto it = mymultiset.emplace(10, "Hello");

// In ra phần tử vừa chèn
std::cout << "Inserted element: (" << it->first << ", " << it->second << ")\n";

// Chèn thêm các phần tử khác
mymultiset.emplace(20, "World");
mymultiset.emplace(10, "Again"); // Chèn trùng lặp

// In ra các phần tử trong multiset
std::cout << "mymultiset:";
for (const auto& p : mymultiset) {
std::cout << " (" << p.first << ", " << p.second << ")";
}
std::cout << '\n'; // Output: mymultiset: (10, Hello) (10, Again) (20, World)

return 0;
}

Với class không hỗ trợ copy/move constructor

#include <iostream>
#include <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;

bool operator<(const NonCopyable& other) const {
return data < other.data;
}
};

int main() {
std::multiset<NonCopyable> mymultiset;

// mymultiset.insert(NonCopyable(10)); // Error: Copy constructor is deleted

mymultiset.emplace(10); // OK: Constructs the element in-place
mymultiset.emplace(20); // OK: Constructs the element in-place

return 0;
}

Các hàm liên quan

emplace_hintXây dựng (construct) một phần tử mới trực tiếp trong std::multiset với một gợi ý (hint)
insertChèn một hoặc nhiều phần tử mới vào std::multiset
eraseXóa một hoặc nhiều phần tử khỏi std::multiset