Có phải là UB để tiếp tục một chức năng thành viên coroutine của một đối tượng có thời gian kết thúc?


9

Câu hỏi này xuất phát từ nhận xét này: Giải thích trọn đời Lambda cho C ++ 20 coroutines

liên quan đến ví dụ này:

auto foo() -> folly::coro::Task<int> {
    auto task = []() -> folly::coro::Task<int> {
        co_return 1;
    }();
    return task;
}

Vì vậy, câu hỏi là liệu thực thi coroutine được trả về foosẽ dẫn đến UB.

"Gọi" một hàm thành viên (sau khi thời gian tồn tại của đối tượng kết thúc) là UB: http://eel.is/c++draft/basic.life#6.2

... Bất kỳ con trỏ nào đại diện cho địa chỉ của vị trí lưu trữ nơi đối tượng sẽ hoặc được định vị đều có thể được sử dụng nhưng chỉ theo những cách giới hạn. [...] Chương trình có hành vi không xác định nếu:

[...]

- con trỏ được sử dụng để truy cập thành viên dữ liệu không tĩnh hoặc gọi hàm thành viên không tĩnh của đối tượng hoặc

Tuy nhiên, trong ví dụ này:

  • các ()nhà điều hành của lambda được gọi trong khi tuổi thọ của lambda vẫn còn hợp lệ
  • Sau đó nó bị đình chỉ,
  • sau đó lambda bị phá hủy,
  • và sau đó hàm thành viên (toán tử ()) được nối lại tại một số điểm sau đó.

Là tiếp tục này được coi là hành vi không xác định?


2
Có thể câu trả lời sau đây có liên quan stackoverflow.com/a/60495359/12345656 Có vẻ khá khác nhau, nhưng đó cũng là về một hàm thành viên trong đó thực thi thiscon trỏ bị vô hiệu. Cũng xem xét các cuộc thảo luận trong các ý kiến.
n314159

Câu trả lời:


2

[dcl.fct.def.coroutine] p3 :

Kiểu hứa của một coroutine là std::coroutine_traits<R, P1, ..., Pn>::promise_type, trong đó Rlà kiểu trả về của hàm và P1 ... Pnlà chuỗi các loại tham số hàm, trước loại tham số đối tượng ẩn (12.4.1) nếu coroutine là không tĩnh chức năng thành viên.

Tham số đối tượng ẩn trong ví dụ của bạn là tham chiếu const và do đó tham chiếu đó sẽ bị treo khi thực thi được nối lại sau khi đối tượng đóng đã bị hủy.

Tuy nhiên, trên lưu ý các đối tượng bị phá hủy trong quá trình thực thi chức năng thành viên, điều này thực sự tốt cho mọi người, và không có gì khác ngoài tiêu chuẩn ngụ ý điều này trong [cơ bản] :

Trước thời gian tồn tại của một đối tượng đã bắt đầu nhưng sau khi lưu trữ mà đối tượng sẽ chiếm giữ đã được phân bổ hoặc, sau khi thời gian tồn tại của một đối tượng kết thúc và trước khi lưu trữ mà đối tượng chiếm giữ được sử dụng lại hoặc giải phóng, bất kỳ con trỏ nào biểu thị địa chỉ của vị trí lưu trữ nơi đối tượng sẽ hoặc được định vị có thể được sử dụng nhưng chỉ trong những cách giới hạn. [...]

void B::mutate() {
  new (this) D2;    // reuses storage --- ends the lifetime of *this
  f();              // undefined behavior
  ... = this;       // OK, this points to valid memory
}

(NB: UB ở trên là do ẩn thiskhông được giặt và vẫn đề cập đến tham số đối tượng ẩn.)

Vì vậy, ví dụ của bạn dường như được xác định rõ ràng, có điều kiện dựa trên ý tưởng rằng việc nối lại thực thi không thuộc các quy tắc giống như một lệnh gọi ban đầu. Lưu ý rằng tham chiếu đến đối tượng đóng có thể bị treo lủng lẳng, nhưng nó không được truy cập theo bất kỳ cách nào giữa đình chỉ và nối lại.


Bạn có nghĩa là việc nối lại và hoàn thành vào cuối năm?
Davis Herring

@DavisHerring Không, ý tôi là cụ thể trong khung thời gian "bên ngoài" đó, trong đó không rõ liệu tham chiếu có thể được gán cho một tham chiếu mới, v.v. sẽ yêu cầu một đối tượng thực sự hay không. Việc tham chiếu không được truy cập theo cách ẩn rất quan trọng vì đây không phải là UB
Columbo

Nhưng nó không đủ để bỏ tham chiếu lơ lửng một mình cho đến khi nối lại; bạn phải để nó một mình ( ví dụ , trong cơ thể lambda) mãi mãi trong suốt quãng đời còn lại của nó, cho đến khi hoàn thành. Vì vậy, có lẽ nó nên bị đình chỉ và hoàn thành.
Davis Herring

@DavisHerring Tôi đặc biệt đề cập đến khoảng đó, bởi vì trong ví dụ của chúng tôi, chúng tôi biết người khác sẽ an toàn.
Columbo

Chắc chắn rồi; Tôi chỉ tìm thấy những từ ngữ khó hiểu. Có lẽ không ai khác làm.
Davis Herring
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.