C ++: ขนาดของวัตถุของคลาสว่างคืออะไร?


111

ฉันสงสัยว่าอะไรจะมีขนาดเท่าออบเจ็กต์ของคลาสว่างได้ มันไม่สามารถแน่นอนสามารถเป็น 0 ไบต์ได้เนื่องจากมันควรจะเป็นไปได้ที่จะอ้างอิงและชี้ไปที่มันเหมือนกับวัตถุอื่น ๆ แต่วัตถุดังกล่าวใหญ่แค่ไหน?

ฉันใช้โปรแกรมขนาดเล็กนี้:

#include <iostream>
using namespace std;

class Empty {};

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

ผลลัพธ์ที่ฉันได้รับจากคอมไพเลอร์ Visual C ++ และ Cygwin-g ++ คือ1 ไบต์ ! นี่เป็นเรื่องที่น่าแปลกใจเล็กน้อยสำหรับฉันเนื่องจากฉันคาดหวังว่ามันจะมีขนาดเท่ากับคำว่าเครื่อง (32 บิตหรือ 4 ไบต์)

ใครช่วยอธิบายได้ไหมว่าทำไมขนาด 1 ไบต์? ทำไมไม่ 4 ไบต์? ขึ้นอยู่กับคอมไพเลอร์หรือเครื่องด้วยหรือเปล่า? นอกจากนี้ใครบางคนสามารถให้เหตุผลที่เป็นประโยชน์มากขึ้นว่าทำไมวัตถุคลาสว่างจึงไม่มีขนาด 0 ไบต์


ฉันไม่เห็นเหตุผลว่าทำไมมันถึงไม่เป็นศูนย์ แต่ด้วยการกำหนดขนาดสิ่งอื่น ๆ จะง่ายกว่าในคอมไพเลอร์ หากคุณมีอาร์เรย์ของสิ่งเหล่านี้แต่ละองค์ประกอบต้องการที่อยู่ที่ไม่ซ้ำกัน ขนาด 1 ทำให้ง่าย
Martin York

2
สามารถมีขนาดเป็นศูนย์ได้หากเป็นวัตถุย่อยระดับฐาน
Johannes Schaub - litb

คำตอบ:


129

การอ้างอิงคำถามที่พบบ่อยเกี่ยวกับสไตล์และเทคนิค C ++ ของ Bjarne Stroustrupสาเหตุที่ขนาดไม่เป็นศูนย์คือ "เพื่อให้แน่ใจว่าที่อยู่ของวัตถุสองชิ้นที่แตกต่างกันจะแตกต่างกัน" และขนาดสามารถเป็น 1 ได้เนื่องจากการจัดตำแหน่งไม่สำคัญที่นี่เนื่องจากไม่มีอะไรให้ดูจริงๆ


55
เขาจะรู้อะไรเกี่ยวกับ C ++? :-)
paxdiablo

18
@Lazer เนื่องจากไม่มีโครงสร้างว่างใน C.
aib

7
@nurabha ตัวชี้นี้จะชี้ไปที่วัตถุ มันไม่ได้ถูกเก็บไว้ในวัตถุ อย่างไรก็ตามหากมีฟังก์ชันเสมือนวัตถุจะมีตัวชี้ไปที่ vtable
tbleher

4
@krish_oza: คุณคิดผิด เมื่อคุณจัดสรรตัวแปรบนสแต็กจะไม่สามารถครอบครองศูนย์ไบต์ได้ (เนื่องจากตัวแปรต่างกันต้องการแอดเดรสที่แตกต่างกัน) ดังนั้นขนาดต่ำสุด 1 หลังจากนั้นก็ขึ้นอยู่กับคอมไพเลอร์ ในทำนองเดียวกันกับnew; เมื่อจัดสรรพื้นที่แล้วการจัดสรรอื่นจะต้องมีที่อยู่อื่น และอื่น ๆ ไม่จำเป็นต้องมีตัวชี้ใด ๆ ที่เกี่ยวข้องกับคลาสว่าง อาจมีตัวชี้ไปยังตัวแปร (หรือการอ้างอิงหรือการจัดสรรภายใน / สแต็ก) แต่ไม่ใช่ขนาดศูนย์และไม่จำเป็นต้องมีขนาดตัวชี้
Jonathan Leffler

3
@Destructor ไม่ใช่คนฉลาด แต่ฉันรู้ว่ายิ้มคืออะไร :-) คุณอาจต้องการอ่านความคิดเห็นซ้ำในแง่นั้นและตระหนักว่ามันเป็นอารมณ์ขัน
paxdiablo

30

มาตรฐานระบุว่าวัตถุที่ได้รับส่วนใหญ่ทั้งหมดมี sizeof ()> = 1:

เว้นแต่จะเป็นบิตฟิลด์ (class.bit) อ็อบเจ็กต์ที่ได้รับส่วนใหญ่จะต้องมีขนาดที่ไม่ใช่ศูนย์และต้องใช้พื้นที่เก็บข้อมูลอย่างน้อยหนึ่งไบต์ วัตถุย่อยคลาสพื้นฐานอาจมีขนาดเป็นศูนย์ ISO / IEC FDIS 14882: 1998 (E) intro วัตถุ


1
ฉันพบว่ามันยากที่จะเชื่อ มาตรฐานออกไปเพื่อให้แน่ใจว่าการใช้งานมีมือที่ว่างในการทำงานที่ดีในการเพิ่มประสิทธิภาพการผูกมือของผู้ใช้งานแบบนั้นฟังดูไม่เหมือนกับสิ่งที่มาตรฐานทำตามปกติ (ฉันอาจจะผิด)
Martin York

4
@eSKay - สิ่งนี้จำเป็นเพื่อให้วัตถุต่างๆได้รับที่อยู่ที่แตกต่างกัน คุณไม่สามารถมีแผนที่ของตัวชี้ไปยังวัตถุได้เช่นหากอินสแตนซ์อื่นมีที่อยู่เดียวกัน
Brian Neal

14

นี่เป็นรายละเอียดการใช้งานจริงๆ เมื่อนานมาแล้วฉันคิดว่ามันอาจเป็นศูนย์ไบต์หรือหนึ่งพันไบต์ซึ่งไม่มีผลกับข้อกำหนดภาษา แต่หลังจากดูมาตรฐานแล้ว (ข้อ 5.3.3) sizeofถูกกำหนดให้ส่งคืนค่าหนึ่งหรือมากกว่าเสมอไม่ว่าจะเป็นอย่างไร

ขนาดของคลาสที่ได้รับส่วนใหญ่จะต้องมากกว่าศูนย์

สิ่งนี้จำเป็นสำหรับสิ่งอื่น ๆ เพื่อให้คุณจัดการอาร์เรย์ของวัตถุและตัวชี้ไปยังพวกมันได้ หากองค์ประกอบของคุณได้รับอนุญาตให้มีขนาดศูนย์ก็&(array[0])จะเหมือนกับ&(array[42])ซึ่งจะทำให้เกิดความหายนะทุกประเภทกับลูปการประมวลผลของคุณ

เหตุผลที่มันอาจไม่ใช่คำเครื่องจักรก็คือไม่มีองค์ประกอบใด ๆ ภายในคำที่ต้องการให้จัดเรียงบนขอบเขตของคำ (เช่นจำนวนเต็ม) ตัวอย่างเช่นหากคุณวางchar x; int y;ไว้ในคลาส GCC ของฉันจะนาฬิกาที่แปดไบต์ (เนื่องจาก int ที่สองต้องอยู่ในแนวเดียวกันในการใช้งานนั้น)


เหตุผลที่ "ไม่เป็นศูนย์" คือวัตถุต่าง ๆ ควรมีที่อยู่ต่างกัน ลองนึกภาพอาร์เรย์ของวัตถุขนาดศูนย์ คุณจะจัดทำดัชนีอย่างไร ในบางกรณีคอมไพเลอร์ได้รับอนุญาตให้ปรับสิ่งนี้ให้เหมาะสมที่สุดแม้ว่า (การเลือกใช้คลาสฐานว่าง)
jalf

@jalf: "คุณจะจัดทำดัชนีอย่างไร" เช่นเดียวกับที่ฉันทำใน C (สำหรับอาร์เรย์ของวัตถุโครงสร้าง) ??
Lazer

1
@eSKay - คุณทำไม่ได้ถ้าพวกเขามีขนาด 0 พวกเขาทั้งหมดอยู่ที่องค์ประกอบ 0
Brian Neal

1
@BrianNeal ซึ่งไม่มีปัญหาเนื่องจากพวกเขาไม่มีรัฐที่จะแยกความแตกต่างของตัวเอง ปัญหาจะมาถึงเมื่อคุณพิจารณาตัวชี้เท่านั้น
gha.st

2
หรือนำขนาดของอาร์เรย์ดังกล่าวมาคำนวณความยาว
gha.st

6

มีข้อยกเว้น: อาร์เรย์ความยาว 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

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

ทำไมไม่มีใครแสดงความคิดเห็นคำตอบนี้ ดูเหมือนอยากรู้มากสำหรับฉัน
Peregring-lk

หากคุณสร้างอ็อบเจกต์ "CompletelyEmpty" สองอ็อบเจกต์ (เช่น 'a' และ 'b') sizeof จะระบุว่ามีความยาว 0 ไบต์ แต่แอดเดรสของมันต่างกัน ('& a == & b' ประเมินเท็จ) และสิ่งนี้จะเป็นไปไม่ได้ ... (โดยใช้ g ++ 4.7.2)
Peregring-lk

1
แต่ถ้าคุณสร้างอาร์เรย์ของวัตถุนี้พูดเป็นc, &c[M] == &c[N]ทุกMและN(เสียงดังกราว ++ 4.1)
Konstantin Nikitin

5
C และ C ++ ไม่อนุญาตให้มีอาร์เรย์ที่มีความยาวเป็นศูนย์ คอมไพเลอร์ของคุณทำได้ แต่ไม่ถูกต้อง
Konrad Borowski

ใช่ขนาดของคลาสนั้นเป็นศูนย์ แต่อินสแตนซ์ของคลาสนี้ยังคงเป็น 1 ไบต์
ZeR0

5

แม้ว่าจะไม่จำเป็นต้องกำหนดหน่วยความจำใด ๆ สำหรับคลาสว่าง แต่ในการสร้างอ็อบเจ็กต์ของคลาสว่างคอมไพเลอร์จะกำหนดหน่วยความจำขั้นต่ำที่สามารถกำหนดได้ซึ่งก็คือ 1 ไบต์ วิธีนี้คอมไพเลอร์สามารถแยกแยะออบเจ็กต์สองชิ้นของคลาสว่างเดียวกันโดยไม่ซ้ำกันและจะสามารถกำหนดแอดเดรสของอ็อบเจ็กต์ให้กับพอยน์เตอร์ของประเภทคลาสว่าง



3

สิ่งนี้อาจช่วยคุณได้ :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

ขนาดของคลาสหรือโครงสร้างว่างคือ 1

สาเหตุที่ทำให้เกิดความร้อนขึ้นในการนำมาตรฐานไปใช้อย่างถูกต้องสิ่งหนึ่งที่มาตรฐาน C ++ กล่าวคือ "ไม่มีวัตถุใดที่จะมีที่อยู่ในหน่วยความจำเหมือนกับตัวแปรอื่น ๆ " .... วิธีใดที่ง่ายที่สุดในการตรวจสอบสิ่งนี้ ตรวจสอบให้แน่ใจว่าทุกประเภทมีขนาดที่ไม่ใช่ศูนย์ เพื่อให้บรรลุสิ่งนี้คอมไพเลอร์จะเพิ่มดัมมี่ไบต์ให้กับโครงสร้างและคลาสที่ไม่มีสมาชิกข้อมูลและไม่มีฟังก์ชันเสมือนเพื่อให้มีขนาด 1 แทนที่จะเป็นขนาด 0 จากนั้นจึงรับประกันว่าจะมีที่อยู่หน่วยความจำที่ไม่ซ้ำกัน


2

การจัดสรร 1 ไบต์สำหรับคลาสว่างขึ้นอยู่กับคอมไพเลอร์ คอมไพเลอร์จำเป็นต้องตรวจสอบให้แน่ใจว่าอ็อบเจ็กต์อยู่ในตำแหน่งหน่วยความจำที่แตกต่างกันและจำเป็นต้องจัดสรรขนาดหน่วยความจำที่ไม่ใช่ศูนย์ให้กับอ็อบเจ็กต์ ฟังบันทึกเกี่ยวกับหัวข้อนี้ที่นี่: http://listenvoice.com/listenVoiceNote.aspx?id=27

แม้ว่าคอมไพเลอร์จะจัดสรรขนาดที่ไม่ใช่ศูนย์ให้กับคลาสว่าง แต่ก็ทำการปรับให้เหมาะสมเมื่อคลาสใหม่มาจากคลาสว่าง ฟังเกี่ยวกับการเพิ่มประสิทธิภาพฐานว่างในคำถามสัมภาษณ์การเขียนโปรแกรม c ++ ของ ListenVoice


2

เหตุผลสำหรับคลาสที่ไม่มีสมาชิกข้อมูล แต่มีขนาด 1 ไบต์คือต้องเก็บ * ข้อความที่แข็งแกร่ง * นี้ไว้ในหน่วยความจำเพื่อให้การอ้างอิงหรือตัวชี้สามารถชี้ไปที่วัตถุของคลาสนั้นได้


0

คลาสว่าง - คลาสนั้นไม่มีเนื้อหาใด ๆ

คลาสใด ๆ ที่ไม่ว่างเปล่าจะแสดงโดยเนื้อหาในหน่วยความจำ

ตอนนี้คลาสว่างจะแสดงในหน่วยความจำอย่างไร? เนื่องจากไม่มีเนื้อหาใดที่จะไม่แสดงการมีอยู่ในหน่วยความจำ แต่มีคลาสอยู่จึงจำเป็นต้องแสดงการมีอยู่ในหน่วยความจำ ในการแสดงคลาสว่างในหน่วยความจำจำเป็นต้องมี 1 ไบต์


0

ฉันคิดว่าเป็นเช่นนั้นเนื่องจาก 1 ไบต์เป็นหน่วยความจำที่เล็กที่สุดที่สามารถใช้เป็นตัวยึดได้และไม่สามารถให้ขนาดเป็นศูนย์ได้เนื่องจากจะไม่สามารถสร้างอาร์เรย์ของวัตถุได้ ..

และสิ่งที่คุณพูดว่า "นี่เป็นเรื่องที่น่าแปลกใจสำหรับฉันเล็กน้อยเนื่องจากฉันคาดหวังว่ามันจะมีขนาดเท่ากับคำว่าเครื่อง (32 บิตหรือ 4 ไบต์)" จะเป็นจริงสำหรับตัวแปรอ้างอิง (คำ macine) ประเภทว่าง () ไม่ใช่ขนาดของคลาสเอง (ซึ่งเป็นประเภทข้อมูลนามธรรม)


0

ฉันคิดว่าคำถามนี้เป็นเพียงความสนใจในเชิงทฤษฎี แต่ไม่สำคัญในทางปฏิบัติ

ตามที่ผู้อื่นชี้ให้เห็นแล้วการได้มาจากคลาสว่างเปล่าไม่ได้ทำอันตรายใด ๆ เนื่องจากจะไม่ใช้หน่วยความจำเพิ่มเติมสำหรับส่วนคลาสพื้นฐาน

ยิ่งไปกว่านั้นถ้าคลาสว่างเปล่า (หมายความว่าในทางทฤษฎี - ไม่จำเป็นต้องมีหน่วยความจำต่ออินสแตนซ์ใด ๆ นั่นคือไม่มีสมาชิกข้อมูลที่ไม่คงที่หรือฟังก์ชันสมาชิกเสมือน) ฟังก์ชันสมาชิกทั้งหมดก็สามารถทำได้เช่นกัน (และควร) ถูกกำหนดให้เป็นแบบคงที่ ดังนั้นจึงไม่จำเป็นต้องสร้างอินสแตนซ์ของคลาสนี้

บรรทัดล่าง: หากคุณพบว่าตัวเองกำลังเขียนคลาส X ว่างให้ทำให้ฟังก์ชันสมาชิกทั้งหมดคงที่ จากนั้นคุณไม่จำเป็นต้องสร้างวัตถุ X และคลาสที่ได้รับจะไม่ได้รับผลกระทบใด ๆ


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;
    }

ผลลัพธ์: โอเคเป็นเรื่องปกติที่จะมีที่อยู่ที่แตกต่างกัน

การส่งคืนขนาด 1 ทำให้แน่ใจว่าวัตถุทั้งสองจะไม่มีที่อยู่เดียวกัน


0

ไม่ใช่ศูนย์เพื่อให้แน่ใจว่าวัตถุทั้งสองจะมีที่อยู่ที่แตกต่างกัน วัตถุที่แตกต่างกันควรมีแอดเดรสที่แตกต่างกันดังนั้นขนาดของคลาสว่างจึงเป็น 1 ไบต์เสมอ


-2

ฉันคิดว่าถ้าขนาดของคลาสว่างเป็นศูนย์หมายความว่าไม่มีอยู่จริง เพื่อให้มีอยู่ (คลาส) จำเป็นต้องมีอย่างน้อย 1 ไบต์เนื่องจากไบต์นี้เป็นที่อยู่หน่วยความจำ / อ้างอิง


-3

เป็นเพราะตัวชี้นี้แม้ว่าตัวชี้จะเป็น (จำนวนเต็ม) 4 ไบต์ แต่หมายถึงตำแหน่งหน่วยความจำเดียว (หนึ่งหน่วย) ซึ่งมีขนาด 1 ไบต์


5
ขออภัยนี่เป็นเรื่องไร้สาระ
jogojapan

@ Narayan das khatri: อันดับแรกประเภทของตัวชี้ขึ้นอยู่กับประเภทข้อมูลซึ่งไม่ใช่ int เสมอไปและขนาดของตัวชี้ที่สองขึ้นอยู่กับเครื่องและคอมไพเลอร์บนเครื่อง 32 บิตคือ 4 ไบต์และสำหรับเครื่อง 64 บิตคือ 8 ไบต์
Krishna Oza
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.