Mục đích của std :: launder là gì?


242

P0137 giới thiệu mẫu hàm std::laundervà thực hiện nhiều, nhiều thay đổi đối với tiêu chuẩn trong các phần liên quan đến công đoàn, trọn đời và con trỏ.

Vấn đề mà bài báo này đang giải quyết là gì? Những thay đổi về ngôn ngữ mà tôi phải nhận thức là gì? Và chúng ta đang làm laundergì?


2
Bạn đang hỏi về chính tờ giấy hay về std::launder? std::launderđược sử dụng để "lấy một con trỏ tới một đối tượng được tạo trong bộ lưu trữ bị chiếm bởi một đối tượng hiện có cùng loại, ngay cả khi nó có const hoặc thành viên tham chiếu."
txtechhelp

7
liên kết hữu ích về chủ đề này. Ngoài ra câu hỏi này stackoverflow.com/questions/27003727/ Mạnh
Paul Rooney

Điều này hiện đã được phát hành trong VC2017 trong phiên bản 15.7.0
Damian

Theo tiêu chuẩn, con trỏ là loại tầm thường nên giặt là không làm gì cả. ;)
tò mò

Câu trả lời:


250

std::launderđược đặt tên một cách khéo léo, mặc dù chỉ khi bạn biết nó dùng để làm gì. Nó thực hiện rửa bộ nhớ .

Xem xét ví dụ trong bài báo:

struct X { const int n; };
union U { X x; float f; };
...

U u = {{ 1 }};

Câu lệnh đó thực hiện khởi tạo tổng hợp, khởi tạo thành viên đầu tiên Uvới {1}.

Bởi vì nlà một constbiến, trình biên dịch có thể tự do cho rằng u.x.nsẽ luôn là 1.

Vì vậy, những gì xảy ra nếu chúng ta làm điều này:

X *p = new (&u.x) X {2};

Xlà tầm thường, chúng ta không cần phải phá hủy đối tượng cũ trước khi tạo một đối tượng mới ở vị trí của nó, vì vậy đây là mã hoàn toàn hợp pháp. Đối tượng mới sẽ có nthành viên là 2.

Vì vậy, hãy nói cho tôi ... những gì sẽ u.x.ntrở lại?

Câu trả lời rõ ràng sẽ là 2. Nhưng điều đó là sai, bởi vì trình biên dịch được phép giả định rằng một constbiến thực sự (không chỉ là một const&, mà là một biến đối tượng được khai báo const ) sẽ không bao giờ thay đổi . Nhưng chúng tôi chỉ thay đổi nó.

[basic.life] / 8 giải thích các trường hợp khi truy cập vào đối tượng mới được tạo thông qua các biến / con trỏ / tham chiếu đến đối tượng cũ. Và có một constthành viên là một trong những yếu tố không đủ tiêu chuẩn.

Vậy ... làm thế nào chúng ta có thể nói về u.x.nđúng?

Chúng ta phải rửa trí nhớ của mình:

assert(*std::launder(&u.x.n) == 2); //Will be true.

Rửa tiền được sử dụng để ngăn chặn mọi người truy tìm nguồn tiền của bạn. Rửa bộ nhớ được sử dụng để ngăn trình biên dịch truy tìm nơi bạn lấy đối tượng của mình, do đó buộc nó phải tránh mọi tối ưu hóa có thể không còn áp dụng.

Một trong những yếu tố không đủ tiêu chuẩn là nếu bạn thay đổi loại đối tượng. std::laundercũng có thể giúp đỡ ở đây:

aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));

[basic.life] / 8 cho chúng tôi biết rằng, nếu bạn phân bổ một đối tượng mới trong bộ lưu trữ của đối tượng cũ, bạn không thể truy cập đối tượng mới thông qua các con trỏ đến đối tượng cũ. laundercho phép chúng tôi bước bên đó.


34
Vì vậy, tl; dr của tôi có đúng không: "về cơ bản là rửa tiền cho loại không phải là UB"?
druckermanly

13
Bạn có thể giải thích tại sao điều này là đúng? "Bởi vì nlà một constbiến, trình biên dịch có thể tự do cho rằng u.x.nsẽ luôn là 1." Nó nói ở đâu trong tiêu chuẩn? Tôi hỏi bởi vì chính vấn đề mà bạn chỉ ra dường như ngụ ý với tôi rằng đó là sai ngay từ đầu. Nó chỉ nên đúng theo quy tắc as-if, thất bại ở đây. Tôi đang thiếu gì?
dùng541686

10
@Mehrdad [basic.life] / 8: " Nếu, [...] một đối tượng mới được tạo tại vị trí lưu trữ mà đối tượng ban đầu chiếm [...] tên của đối tượng ban đầu sẽ tự động đề cập đến đối tượng mới [...] if: [...] loại [...] không chứa bất kỳ thành viên dữ liệu không tĩnh nào có loại đủ điều kiện hoặc loại tham chiếu [...] "
ecatmur

14
@Băng Rất; nếu không có đối tượng loại T nằm ở địa chỉ ptrđại diện, thì bạn sẽ phá vỡ launderđiều kiện tiên quyết, vì vậy không có lý do nào để nói về kết quả.
TC

17
@NicolBolas Người ta chỉ có thể hy vọng supercat thực hiện nhiều hoạt động của Ủy ban khi họ trả lời không ngừng đòi hỏi từ những người sử dụng ngôn ngữ của bên thứ ba trên SO. Bên cạnh đó, một trình biên dịch tối ưu hóa tốt sẽ tối ưu hóa giải pháp đúng lại memcpythành một lối trình diễn tại chỗ trên các nền tảng (tức là lỏng lẻo liên kết) được hỗ trợ nào .
gạch dưới
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.