Có thể có các đối tượng ngầm khác nhau dựa trên quyết định thời gian chạy sau này trong C ++ 20 không?


11

Câu hỏi này đề cập đến việc bổ sung P0593 vào dự thảo C ++ 20 mới nhất .

Đây là ví dụ của tôi:

#include <cstdlib>
#include <cstdio>

void foo(void *p)
{
    if ( std::getchar() == 'i' )
    {
        *(int *)p = 2;
        std::printf("%d\n", *(int *)p);
    }
    else
    {
        *(float *)p = 2;
        std::printf("%f\n", *(float *)p);
    }
}

int main()
{
    void *a = std::malloc( sizeof(int) + sizeof(float) );
    if ( !a ) return EXIT_FAILURE;

    foo(a);
    // foo(a);    [2]
}

Mã này có được xác định rõ cho tất cả các đầu vào theo dự thảo mới nhất không?

Lý do được trình bày trong P0593 cho thấy khá rõ rằng việc không ghi chú [2]sẽ dẫn đến hành vi không xác định do vi phạm bí danh nghiêm ngặt, nếu hai mục nhập của người dùng khác nhau. Việc tạo đối tượng ngầm được cho là xảy ra chỉ một lần, tại điểm malloc; nó không được kích hoạt bởi câu lệnh gán trong foo.

Đối với bất kỳ hoạt động thực tế nào của chương trình, tồn tại một thành viên của tập hợp các đối tượng ẩn không xác định sẽ làm cho chương trình được xác định rõ. Nhưng tôi không rõ liệu lựa chọn tạo đối tượng ngầm được đề cập trong [intro.object] / 10 phải được thực hiện khi mallocxảy ra hay không; hoặc liệu quyết định có thể "du hành thời gian".

Vấn đề tương tự có thể phát sinh đối với một chương trình đọc một blob nhị phân vào bộ đệm và sau đó đưa ra quyết định về thời gian chạy về cách truy cập nó (ví dụ như khử lưu huỳnh; và tiêu đề cho chúng ta biết liệu float hay int sắp xuất hiện).

Câu trả lời:


9

Việc tạo đối tượng ngầm được cho là xảy ra chỉ một lần, tại điểm malloc; nó không được kích hoạt bởi câu lệnh gán trong foo.

Điều đó không liên quan. Điều quan trọng là đối tượng nào được tạo ra. Tiêu chuẩn nói rằng đối tượng được tạo là một đối tượng tạo ra thứ gì đó đã được UB thành mã được xác định rõ:

hoạt động đó hoàn toàn tạo và bắt đầu thời gian tồn tại của 0 hoặc nhiều đối tượng của các kiểu tuổi thọ ngầm ([basic.types]) trong vùng lưu trữ được chỉ định của nó nếu làm như vậy sẽ dẫn đến chương trình có hành vi được xác định.

Hành vi cuối cùng dựa trên thực thi thời gian chạy, không phải phân tích tĩnh. Vì vậy, bạn chỉ cần theo dõi quá trình thực thi chương trình cho đến khi bạn gặp phải trường hợp không xác định được hành vi, nhưng sẽ được xác định nếu một đối tượng thuộc loại nào đó đã được tạo trong bộ lưu trữ đó tại thời điểm thao tác được đề cập.

Vì vậy, vị trí của sáng tạo luôn là "hoạt động", nhưng việc xác định những gì được tạo ra dựa trên cách bộ nhớ được sử dụng trong thời gian chạy (ví dụ: hành vi).


2
Để rõ ràng, bạn đang nói rằng mã của tôi được xác định rõ?
MM

2
@MM: Đúng vậy.
Nicol Bolas
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.