C ++: Kích thước của một đối tượng của một lớp rỗng là bao nhiêu?


111

Tôi đã tự hỏi những gì có thể là kích thước của một đối tượng của một lớp trống . Nó chắc chắn không thể là 0 byte vì nó có thể tham chiếu và trỏ đến nó giống như bất kỳ đối tượng nào khác. Nhưng, một đối tượng như vậy lớn đến mức nào?

Tôi đã sử dụng chương trình nhỏ này:

#include <iostream>
using namespace std;

class Empty {};

int main()
{
    Empty e;
    cerr << sizeof(e) << endl;
    return 0;
}

Đầu ra tôi nhận được trên cả hai trình biên dịch Visual C ++ và Cygwin-g ++ đều là 1 byte ! Điều này khiến tôi hơi ngạc nhiên vì tôi đã mong đợi nó có kích thước bằng từ máy (32 bit hoặc 4 byte).

Bất cứ ai có thể giải thích tại sao kích thước của 1 byte? Tại sao không phải là 4 byte? Điều này phụ thuộc vào trình biên dịch hay máy tính? Ngoài ra, ai đó có thể đưa ra một lý do cụ thể hơn cho lý do tại sao một đối tượng lớp trống sẽ không có kích thước 0 byte?


Tôi không hiểu tại sao nó không thể bằng không. Nhưng bằng cách cung cấp cho nó một kích thước khác, mọi thứ dễ dàng hơn trong trình biên dịch. Nếu bạn có một mảng những thứ này thì mỗi phần tử cần một địa chỉ duy nhất. Kích thước 1 làm cho việc này trở nên dễ dàng.
Martin York

2
Nó có thể có kích thước bằng 0 nếu nó là một subobject lớp cơ sở.
Johannes Schaub - litb

Câu trả lời:


129

Trích dẫn Câu hỏi thường gặp về phong cách và kỹ thuật C ++ của Bjarne Stroustrup , lý do kích thước khác 0 là "Để đảm bảo rằng địa chỉ của hai đối tượng khác nhau sẽ khác nhau." Và kích thước có thể là 1 vì căn chỉnh không quan trọng ở đây, vì thực tế không có gì để xem xét.


55
Bah, anh ta biết cái quái gì về C ++? :-)
paxdiablo

18
@Lazer, vì không có cấu trúc trống nào trong C.
aib

7
@nurabha Con trỏ này trỏ đến đối tượng. Nó không được lưu trữ trong đối tượng. Tuy nhiên, nếu có các hàm ảo, thì đối tượng chứa một con trỏ đến vtable.
tbleher 19/09/13

4
@krish_oza: bạn nghĩ sai rồi. Khi bạn cấp phát một biến trên ngăn xếp, nó không thể chiếm không byte (vì các biến khác nhau cần các địa chỉ khác nhau), do đó kích thước tối thiểu là 1. Sau đó, nó là vào trình biên dịch. Tương tự với new; khi không gian được cấp phát, phân bổ khác phải có địa chỉ khác. Và như thế. Không nhất thiết phải có bất kỳ con trỏ nào liên quan đến lớp trống; có thể có con trỏ đến các biến (hoặc tham chiếu, hoặc phân bổ cục bộ / ngăn xếp), nhưng chúng không có kích thước bằng 0 và chúng không nhất thiết phải là kích thước con trỏ.
Jonathan Leffler

3
@Destructor, không phải là người thông minh nhưng tôi biết mặt cười là gì :-) Bạn có thể muốn đọc lại bình luận trong ánh sáng đó và nhận ra đó là sự hài hước.
paxdiablo

30

Tiêu chuẩn nói rằng tất cả các đối tượng dẫn xuất hầu hết đều có sizeof ()> = 1:

Trừ khi nó là một trường bit (class.bit), một đối tượng dẫn xuất nhất sẽ có kích thước khác 0 và sẽ chiếm một hoặc nhiều byte dung lượng lưu trữ. Các đối tượng con của lớp cơ sở có thể có kích thước bằng không. ISO / IEC FDIS 14882: 1998 (E) intro.object


1
Tôi thấy khó tin. Tiêu chuẩn ra đời để đảm bảo việc triển khai có một bàn tay rảnh rỗi để thực hiện tốt công việc tối ưu hóa, buộc tay người triển khai như vậy không giống như cách mà tiêu chuẩn thường làm (tôi có thể sai)
Martin York

4
@eSKay - Điều này là bắt buộc để các đối tượng khác nhau nhận được các địa chỉ khác nhau. Ví dụ: bạn không thể có bản đồ con trỏ tới các đối tượng, nếu các trường hợp khác nhau có cùng địa chỉ.
Brian Neal

14

Đó thực sự là một chi tiết triển khai. Cách đây rất lâu, tôi nghĩ nó có thể là 0 byte hoặc một nghìn byte, nó không liên quan đến đặc tả ngôn ngữ. Tuy nhiên, sau khi xem xét tiêu chuẩn (phần 5.3.3), sizeofđược định nghĩa là luôn trả về một hoặc lớn hơn, bất kể điều gì.

Kích thước của một lớp dẫn xuất nhất phải lớn hơn 0.

Điều này là cần thiết, trong số những thứ khác, cho phép bạn xử lý các mảng đối tượng và con trỏ tới chúng. Nếu các phần tử của bạn được phép có kích thước bằng 0 thì &(array[0])sẽ giống hệt với &(array[42]), điều này sẽ gây ra tất cả các loại tàn phá cho các vòng xử lý của bạn.

Lý do tại sao nó có thể không phải là một từ máy là không có phần tử nào bên trong nó thực sự yêu cầu nó phải được căn chỉnh trên một ranh giới từ (chẳng hạn như một số nguyên). Ví dụ: nếu bạn đặt char x; int y;bên trong lớp, GCC của tôi sẽ đồng hồ nó ở tám byte (vì int thứ hai phải được căn chỉnh trong triển khai đó).


Lý do cho "not zero" là các đối tượng khác nhau nên có các địa chỉ khác nhau. Hãy tưởng tượng một mảng các đối tượng có kích thước bằng không. Bạn sẽ lập chỉ mục nó như thế nào? Trong một số trường hợp, trình biên dịch được phép tối ưu hóa này đi mặc dù (các lớp cơ sở có sản phẩm nào optmization)
jalf

@jalf: "Bạn sẽ lập chỉ mục nó như thế nào?" Giống như cách tôi sẽ làm trong C (ví dụ: đối với một mảng các đối tượng cấu trúc) ??
Lazer

1
@eSKay - Bạn không thể nếu chúng có kích thước 0. Tất cả chúng sẽ ở phần tử 0.
Brian Neal

1
@BrianNeal không có vấn đề gì, vì họ không có trạng thái để phân biệt chính mình. Các vấn đề chỉ đến khi bạn xem xét các con trỏ.
gha.st

2
Hoặc lấy kích thước của mảng đã nói để tính chiều dài của nó.
gha.st

6

Có một ngoại lệ: mảng độ dài 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

int main(int argc, const char** argv) {
  std::cout << sizeof(CompletlyEmpty) << '\n';
}

Tại sao không ai bình luận câu trả lời này? Nó có vẻ rất tò mò đối với tôi.
Peregring-lk,

Nếu bạn tạo hai đối tượng "CompleteEmpty" (ví dụ: 'a' và 'b'), sizeof cho biết chúng dài 0 byte, nhưng địa chỉ của nó là khác nhau ('& a == & b' đánh giá sai). Và điều này là không thể ... (sử dụng g ++ 4.7.2).
Peregring-lk,

1
Nhưng nếu bạn tạo một mảng các đối tượng này, chẳng hạn c, &c[M] == &c[N]cho mọi MN(clang ++ 4.1).
Konstantin Nikitin

5
C và C ++ không cho phép mảng có độ dài bằng không. Trình biên dịch của bạn có thể, nhưng nó không chính xác.
Konrad Borowski

có, kích thước Lớp chính nó là 0, nhưng một thể hiện của lớp này vẫn là 1 byte.
ZeR0

5

Mặc dù không bắt buộc phải gán bất kỳ bộ nhớ nào cho một lớp trống, nhưng để tạo các đối tượng của các lớp trống, trình biên dịch sẽ gán bộ nhớ tối thiểu có thể được gán, đó là 1 byte. Bằng cách này, trình biên dịch có thể phân biệt duy nhất hai đối tượng của cùng một lớp rỗng và sẽ có thể gán địa chỉ của đối tượng cho một con trỏ của loại lớp trống.



3

Điều này có thể giúp ích cho bạn :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-osystem-1-a

Kích thước của một lớp hoặc cấu trúc trống là 1

Lý do điều này xảy ra là do việc triển khai đúng tiêu chuẩn, một trong những điều mà tiêu chuẩn C ++ nói là "không đối tượng nào có cùng địa chỉ trong bộ nhớ với bất kỳ biến nào khác" .... Cách dễ nhất để đảm bảo điều này là gì? Đảm bảo rằng tất cả các loại đều có kích thước khác 0. Để đạt được điều này, trình biên dịch thêm một byte giả vào các cấu trúc và lớp không có thành viên dữ liệu và không có hàm ảo để chúng có kích thước 1 thay vì kích thước 0 và sau đó chúng được đảm bảo có một địa chỉ bộ nhớ duy nhất.


2

Việc phân bổ 1 byte cho một lớp trống phụ thuộc vào trình biên dịch. Các trình biên dịch cần đảm bảo các đối tượng nằm ở các vị trí bộ nhớ khác nhau và chúng cần phân bổ kích thước bộ nhớ khác 0 cho một đối tượng. Nghe ghi chú về chủ đề này tại đây: http://listenvoice.com/listenVoiceNote.aspx?id=27

Mặc dù các trình biên dịch phân bổ kích thước khác 0 cho một lớp trống, chúng cũng thực hiện tối ưu hóa khi các lớp mới có nguồn gốc từ các lớp trống. Nghe về tối ưu hóa cơ sở trống trong các câu hỏi phỏng vấn lập trình c ++ của ListenVoice.


2

lý do cho lớp không có thành viên dữ liệu nhưng có kích thước 1 byte là * văn bản mạnh * này phải được lưu trữ trong bộ nhớ để một tham chiếu hoặc con trỏ có thể trỏ đến đối tượng của lớp đó


0

lớp trống - lớp đó không chứa bất kỳ nội dung nào.

bất kỳ lớp nào không trống sẽ được đại diện bởi nội dung của nó trong bộ nhớ.

bây giờ lớp trống sẽ được biểu diễn như thế nào trong bộ nhớ? vì nó không có nội dung nên không có cách nào để hiển thị sự tồn tại của nó trong bộ nhớ, nhưng lớp hiện diện, bắt buộc phải hiển thị sự hiện diện của nó trong bộ nhớ. Để hiển thị sự hiện diện của lớp trống trong bộ nhớ, cần có 1 byte.


0

Tôi nghĩ là như vậy bởi vì 1 byte là đơn vị bộ nhớ nhỏ nhất có thể được sử dụng làm trình giữ chỗ và nó không thể cung cấp kích thước bằng 0 vì sẽ không thể tạo một mảng đối tượng ..

và điều bạn nói "Điều này hơi ngạc nhiên với tôi vì tôi đã mong đợi nó có kích thước bằng từ máy (32 bit hoặc 4 byte)." sẽ đúng với biến tham chiếu (các từ macine) có kiểu trống (), không đúng với kích thước của chính lớp (là kiểu dữ liệu trừu tượng),


0

Tôi nghĩ câu hỏi này chỉ quan tâm đến lý thuyết nhưng không quan trọng trong thực tế.

Như đã được chỉ ra bởi những người khác, dẫn xuất từ ​​một lớp trống không gây hại gì, vì điều này sẽ không tiêu tốn thêm bất kỳ bộ nhớ nào cho phần lớp cơ sở.

Hơn nữa, nếu một lớp trống (có nghĩa là nó - về mặt lý thuyết - không cần bất kỳ bộ nhớ cho mỗi trường hợp nào, tức là nó không có bất kỳ thành viên dữ liệu không tĩnh nào hoặc các hàm thành viên ảo) thì tất cả các hàm thành viên của nó cũng có thể (và nên) được định nghĩa là tĩnh. Vì vậy, không cần phải tạo một thể hiện của lớp này.

Điểm mấu chốt: Nếu bạn thấy mình đang viết một lớp X trống thì chỉ cần đặt tất cả các hàm thành viên là tĩnh. Sau đó, bạn sẽ không cần tạo đối tượng X và các lớp dẫn xuất sẽ không bị ảnh hưởng theo bất kỳ cách nào.


0
#include<iostream>
using namespace std;


    class Empty { };
    int main()
    {
        Empty* e1 = new Empty;
        Empty* e2 = new Empty;

        if (e1 == e2)
            cout << "Alas same address of two objects" << endl;
        else
            cout << "Okay it's Fine to have different addresses" << endl;

        return 0;
    }

Đầu ra: Được rồi, không sao khi có các địa chỉ khác nhau

Trả về kích thước 1 đảm bảo rằng hai đối tượng sẽ không có cùng địa chỉ.


0

Nó là nonzero để đảm bảo rằng hai đối tượng khác nhau sẽ có địa chỉ khác nhau. Các đối tượng khác nhau nên có địa chỉ khác nhau, vì vậy kích thước của một lớp trống luôn là 1 byte.


-2

Tôi nghĩ rằng nếu kích thước của một lớp trống bằng 0 thì có nghĩa là nó không tồn tại. Để nó (lớp) tồn tại, nó yêu cầu phải có ít nhất 1 byte, vì byte này là địa chỉ bộ nhớ / tham chiếu.


-3

Đó là vì con trỏ này , mặc dù con trỏ là (số nguyên) 4 byte nhưng nó chỉ đến một vị trí bộ nhớ (một Đơn vị) là 1 byte.


5
Xin lỗi, nhưng điều này là vô nghĩa.
jogojapan

@Narayan das khatri: đầu tiên loại con trỏ phụ thuộc vào kiểu dữ liệu không phải là int luôn luôn và thứ hai kích thước của con trỏ phụ thuộc vào máy và trình biên dịch trên máy 32 bit là 4 byte và đối với máy 64 bit là 8 byte.
Krishna Oza
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.