Tại sao chúng ta không thể tạo các đối tượng có thể xây dựng tầm thường bằng malloc nếu hàm tạo mặc định tầm thường thực hiện không có hành động?


14

Tôi gặp khó khăn trong việc hiểu đoạn văn sau được trích dẫn từ cppreference về hàm tạo mặc định tầm thường. Tôi đã tìm kiếm stackoverflow nhưng vẫn không nhận được câu trả lời rõ ràng. Vì vậy, xin vui lòng giúp đỡ.

Một constructor mặc định tầm thường là một constructor thực hiện không có hành động. Tất cả các loại dữ liệu tương thích với ngôn ngữ C (loại POD) đều có thể xây dựng mặc định. Tuy nhiên, không giống như trong C, các đối tượng có hàm tạo mặc định tầm thường không thể được tạo bằng cách đơn giản diễn giải lại bộ lưu trữ được căn chỉnh phù hợp, chẳng hạn như bộ nhớ được cấp phát với std :: malloc: vị trí mới được yêu cầu để chính thức giới thiệu một đối tượng mới và tránh hành vi không xác định tiềm năng.

Cụ thể, nếu hàm tạo mặc định tầm thường không làm gì, tại sao chúng ta không thể diễn giải lại bộ lưu trữ và giả vờ có một đối tượng với kiểu đã cho? Bạn có thể vui lòng cung cấp một số ví dụ cho hành vi không xác định tiềm năng mà điều này sẽ gây ra?


Công việc quan trọng nhất của trình biên dịch không phải là biên dịch mã nguồn mà là từ chối mã có thể không hợp lệ. Nó không thể làm điều này khi bạn sử dụng malloc ().
Hans Passant

6
Những lý do rất đơn giản. Càng ít cơ hội để lập trình viên làm những điều điên rồ, thì càng có nhiều cơ hội cho trình biên dịch làm những điều điên rồ (tối ưu hóa áp lực).
n. 'đại từ' m.

1
Vì những lý do tương tự mà bạn không thể chỉ *reinterpret_cast<float*>(&someNonFloatObject) = 0.1f;. C ++ có khái niệm về các đối tượng và tuổi thọ đối tượng, được chỉ định trên máy trừu tượng và chỉ vì không có lệnh CPU để tạo đối tượng từ bộ lưu trữ không có nghĩa là không có sự khác biệt trên máy trừu tượng.
Max Langhof

1
@HansPassant Trình biên dịch từ chối tất cả mã từ chối tất cả mã không hợp lệ. Dù sao, việc từ chối các chương trình có UB.
n. 'đại từ' m.

Câu trả lời:


7

P0593R5 đưa ra ví dụ này:

struct X { int a, b; };
X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}

và giải thích:

Khi được biên dịch bằng trình biên dịch C ++, mã này có hành vi không xác định, bởi vì p-> cố gắng ghi vào một tiểu dự án int của một đối tượng X và chương trình này không bao giờ tạo ra một đối tượng X cũng như một đối tượng con int.

Mỗi [intro.object] p1,

Một đối tượng được tạo bởi một định nghĩa, bởi một biểu thức mới, khi thay đổi hoàn toàn thành viên tích cực của liên minh hoặc khi một đối tượng tạm thời được tạo.

... Và chương trình này không làm những điều này.

Trong thực tế công việc này và tình huống UB được coi là một khiếm khuyết trong tiêu chuẩn hơn bất cứ điều gì khác. Toàn bộ mục tiêu của bài viết là đề xuất một cách khắc phục vấn đề đó và các trường hợp tương tự mà không phá vỡ những thứ khác.


1

Vì lý do "tinh khiết".

Sự thay thế và hiện trạng thực tế là mọi khu vực lưu trữ sẽ chứa tất cả các đối tượng phù hợp trong bộ lưu trữ đó cùng một lúc. Một số thành viên ủy ban không thoải mái với hiện trạng và rất nhiều người sợ khái niệm có vô số đối tượng ở cùng một nơi (trong trạng thái ảo, chưa được khởi tạo).

Không ai từng có thể chỉ ra một vấn đề logic với việc có vô số đối tượng trong một vùng lưu trữ.

Bởi vì họ có các phần khác nhau của tiêu chuẩn nói những điều mâu thuẫn, các thành viên ủy ban chỉ quyết định thực hiện nghiêm túc một trong những phần tồi tệ nhất của tiêu chuẩn.

Ngoài ra, sử dụng chuỗi ký tự là hoàn toàn không được phép, nếu bạn thực sự nghiêm túc thực hiện một phần của tiêu chuẩn.


sử dụng chuỗi ký tự là hoàn toàn không được phép Trong chứng thư. Có vấn đề CWG tương tự về type_infocác đối tượng. Bạn đã báo cáo 'bout chuỗi chữ?
Luật sư ngôn ngữ
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.