ความแตกต่างระหว่าง 'new operator' และ 'operator new'?


126

"ตัวดำเนินการใหม่" และ "ตัวดำเนินการใหม่" ต่างกันอย่างไร


3
สวัสดีคุณช่วยชี้แจงคำถามได้ไหม ดูเหมือนว่ามีการพิมพ์ผิดบางที่
Dima Malenko

17
คำถามมีคำที่ถูกต้องดูคำตอบด้านล่าง วิธีการจัดสรรหน่วยความจำแบบไดนามิกคือการใช้ตัวnewดำเนินการ ตัวดำเนินการนี้สามารถโอเวอร์โหลดได้ ในการแยกความแตกต่างระหว่างตัวดำเนินการเริ่มต้นกับเวอร์ชันที่โอเวอร์โหลดค่าเริ่มต้นเรียกว่า "ตัวดำเนินการใหม่" และเวอร์ชันที่โอเวอร์โหลดเรียกว่า "ตัวดำเนินการใหม่"
Thomas Matthews

2
วิธีการทำ ฉันใหม่และไม่รู้สึกตัว
Sandeep

คำตอบ:


127

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

Operator new เป็นฟังก์ชั่นที่จัดสรรหน่วยความจำดิบ - อย่างน้อยแนวคิดก็ไม่แตกต่างจากmalloc(). แม้ว่าจะค่อนข้างผิดปกติเว้นแต่คุณจะเขียนบางอย่างเช่นคอนเทนเนอร์ของคุณเอง แต่คุณสามารถโทรหาโอเปอเรเตอร์ใหม่ได้โดยตรงเช่น:

char *x = static_cast<char *>(operator new(100));

นอกจากนี้ยังสามารถโอเวอร์โหลดโอเปอเรเตอร์ใหม่ได้ทั่วโลกหรือสำหรับคลาสเฉพาะ IIRC ลายเซ็นคือ:

void *operator new(size_t);

แน่นอนว่าหากคุณโหลดโอเปอเรเตอร์ใหม่มากเกินไป (ทั้งส่วนกลางหรือสำหรับคลาส) คุณจะต้องการ / จำเป็นต้องโอเวอร์โหลดตัวดำเนินการที่ตรงกันลบด้วยเช่นกัน สำหรับสิ่งที่คุ้มค่านอกจากนี้ยังมีตัวดำเนินการใหม่ [] แยกต่างหากที่ใช้ในการจัดสรรหน่วยความจำสำหรับอาร์เรย์ แต่คุณเกือบจะดีกว่าที่จะเพิกเฉยต่อความยุ่งเหยิงทั้งหมดอย่างสิ้นเชิง

ตัวดำเนินการใหม่คือสิ่งที่คุณใช้สร้างออบเจ็กต์จากร้านค้าฟรี:

my_class *x = new my_class(0);

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


18
+1 สำหรับการใช้วลีที่แตกต่างกันมาตรฐานจะใช้นิพจน์ใหม่ทุกรอบและใช้เพียงครั้งเดียวเท่านั้นที่ใช้โอเปอเรเตอร์ใหม่เพื่ออ้างถึงสถานที่โทร ฉันมักจะทำเช่นเดียวกัน: ตัวดำเนินการใหม่สำหรับตัวจัดสรรและนิพจน์ใหม่สำหรับการใช้งาน
David Rodríguez - dribeas

3
นิพจน์ใหม่คือวลีทั้งหมดที่ขึ้นต้นด้วยใหม่ แล้วคุณเรียกแค่ส่วน "ใหม่" ของมันว่าอะไร? หากเรียกตัวดำเนินการใหม่นั้นไม่ถูกต้องเราไม่ควรเรียก "sizeof" ว่าโอเปอเรเตอร์ sizeof หรือ & ที่อยู่ของโอเปอเรเตอร์ (เมื่อมันทำงานเหมือนตัวดำเนินการ)
Kaz

1
จากคำพูดของ Kaz อาจจะมีการเปลี่ยนคำถามว่าอะไรคือความแตกต่างระหว่างตัวดำเนินการใหม่กับตัวดำเนินการใหม่ :)
CS

2
"ตัวดำเนินการใหม่" เทียบกับ "คำหลักใหม่"
user997112

2
@antred: operator delete(x);คุณต้องการปล่อยที่กับสิ่งที่ต้องการ
Jerry Coffin

35

"ตัวดำเนินการใหม่"

class Foo
{
public:
        void* operator new( size_t );
}

"ตัวดำเนินการใหม่":

Foo* foo = new Foo();

ในตัวอย่างนี้new Foo()โทรFoo::operator new()

กล่าวอีกนัยหนึ่ง "โอเปอเรเตอร์ใหม่" เรียก " operator new()" เช่นเดียวกับการเรียก + โอเปอเรเตอร์operator +()


13
newไม่ใช่ตัวดำเนินการใน C ++ sizeofยกตัวอย่างเช่นเป็นผู้ดำเนินการ แต่newและdeleteไม่ได้ newและdeleteมีคำหลักและโครงสร้างประโยคว่าคำเหล่านี้จะเรียกว่ารูปแบบใหม่การแสดงออกและลบแสดงออก
AnT

2
เอ่อถ้ามีอะไรsizeofเป็นโครงสร้างทางวากยสัมพันธ์newและdeleteเป็นตัวดำเนินการที่ถูกต้องถูกกฎหมายและสามารถโอเวอร์โหลดได้ จากทุกสิ่งที่ฉันเคยเห็นnewและdeleteเป็นทั้งผู้ดำเนินรายการ ดู [cplusplus.com] [ cplusplus.com/doc/tutorial/classes2/]
Austin Hyde

7
ไม่ถูกต้อง คำศัพท์ C ++ อย่างเป็นทางการคือคำศัพท์ที่กำหนดโดยข้อกำหนดภาษาไม่ใช่โดยบางเว็บไซต์ ในข้อกำหนดภาษาไม่มี therm เป็น "ตัวดำเนินการใหม่" แต่มีคำว่า " operator newfunction" อีกครั้งsizeofเป็นอย่างชัดแจ้งจะเรียกว่าเป็น "ผู้ประกอบการ" ในขณะที่newและdeleteจะไม่เรียกว่าเป็นผู้ประกอบการ
AnT

6
AndreyT: ไม่ถูกต้อง มาตรฐาน C ++ เรียกตัวดำเนินการ 'ใหม่' ดู 13.5 / 1

3
@AndreyT: ฉันคิดอย่างที่คุณทำตัวดำเนินการใหม่คือตัวจัดสรรและนิพจน์ใหม่ที่ใช้ เราได้ตรวจสอบและการตรวจสอบว่าใน§5.3.4 / 3 ใช้มาตรฐานในปัจจุบันคำประกอบการใหม่ ต่อมาใน§5.3.4 / 8 จะตั้งชื่อฟังก์ชันตัวจัดสรรเป็นตัวดำเนินการใหม่และตัวดำเนินการใหม่ []
David Rodríguez - dribeas

22

ต่อไปนี้เป็นคำพูดจากหนังสือ C ++ ที่มีประสิทธิภาพมากขึ้นจาก Scott Meyers:

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


7
เห็นได้ชัดว่าคำนี้ประดิษฐ์ขึ้นโดยผู้เขียนหนังสือ (หรืออาจยืมมาจากแหล่งข้อมูลที่ล้าสมัย) ในระบบการตั้งชื่อ C ++ ที่เป็นทางการไม่มีคำว่า "ตัวดำเนินการใหม่"
AnT

2
@AndreyT: ฉันค้นหา C ++ 11 สำหรับ "ตัวดำเนินการใหม่" และพบว่ามีการอ้างอิงถึงสี่ตำแหน่ง โดยเฉพาะอย่างยิ่งการอ้างอิงสองรายการเกี่ยวกับ "ตำแหน่งตัวดำเนินการใหม่"
Mooing Duck

11

ไม่มีความแตกต่างระหว่าง "ตัวดำเนินการใหม่" และ "ตัวดำเนินการใหม่" ทั้งสองอ้างถึงสิ่งเดียวกัน: operator newฟังก์ชันโอเวอร์โหลด / เปลี่ยนได้ซึ่งโดยทั่วไปจะทำการจัดสรรหน่วยความจำดิบสำหรับอ็อบเจ็กต์ที่สร้างโดยนิพจน์ใหม่

โปรดทราบว่าไม่มีคำศัพท์ใดอยู่ในข้อกำหนดภาษา (ซึ่งเป็นแหล่งที่มาของคำศัพท์ที่เป็นทางการ)

เมื่อคุณใช้newในโปรแกรมเพื่อสร้างออบเจ็กต์จะเรียกว่านิพจน์ใหม่ นิพจน์ใหม่ประกอบด้วยคำสำคัญnewและส่วนไวยากรณ์เพิ่มเติมที่กำหนดโดยไวยากรณ์ ไม่มีส่วนใดของไวยากรณ์ของนิพจน์นี้ที่เรียกว่า "ตัวดำเนินการ"

ฟังก์ชันการจัดสรรหน่วยความจำดิบoperator newเรียกอย่างเป็นทางการว่า " operator newฟังก์ชัน" โปรดทราบว่าคำoperatorและnewในลำดับนี้เป็นเพียงคำหลักภาษา C ++ สองคำที่แยกจากกัน พวกเขาไม่ได้สร้างคำศัพท์ภาษาอังกฤษว่า "operator new" ไม่มีที่ไหนในข้อกำหนดภาษาคุณจะพบการอ้างอิงถึง "operator new" เป็นศัพท์ภาษาอังกฤษ ทุกครั้งนี่เป็นเพียงการรวมกันของคำหลักสองคำที่เป็นอิสระซึ่งสร้างไวยากรณ์การประกาศสำหรับฟังก์ชันการจัดสรรหน่วยความจำ

อีกครั้งในประวัติย่อ: อย่างเป็นทางการใน C ++ ไม่มีคำศัพท์ภาษาอังกฤษเช่น "operator new" หรือ "new operator" ลำดับเดิมมีอยู่ในข้อกำหนดของภาษาโดยเป็นเพียงคำหลักที่ผสมกันไม่ใช่คำในภาษาอังกฤษ ตอนหลังไม่อยู่เลย


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

7

เมื่อคุณสร้างออบเจ็กต์ใหม่หน่วยความจำจะถูกจัดสรรโดยใช้ตัวดำเนินการใหม่จากนั้นตัวสร้างจะถูกเรียกเพื่อเริ่มต้นหน่วยความจำ ตัวดำเนินการใหม่ทำทั้งการจัดสรรและการเริ่มต้นโดยที่ตัวดำเนินการใหม่จะทำการจัดสรรเท่านั้น


6

คำถามของ OP ใช้วลีไม่ถูกต้อง เป็นการดีกว่าที่จะแบ่งเฟสเป็น 'ความแตกต่างระหว่าง' ตัวดำเนินการใหม่ 'และ' นิพจน์ใหม่ '? หมายเหตุ 'operator new' มักจะหมายถึง 'operator new function' เช่นกัน

และมีคำตอบที่ถูกต้องมากมายด้านล่างนี้เป็นของฉัน:

1> 'นิพจน์ใหม่' เรียกตัวดำเนินการ 'ใหม่' เพื่อจัดสรรหน่วยความจำดิบจากนั้นเรียกตัวสร้าง

apple * p = new apple(); //new expression

2> 'operator new' จัดสรรหน่วยความจำดิบเท่านั้นไม่แตกต่างจาก malloc มากนัก

void* mem = operator new(sizeof(apple)); //just like calling malloc()
apple* p2 = new(mem) apple(1); //call construct here using placement new.

2

ตัวดำเนินการใหม่ : C ++ รองรับการจัดสรรวัตถุแบบไดนามิกโดยใช้ตัวดำเนินการใหม่ ตัวดำเนินการใหม่จะจัดสรรหน่วยความจำสำหรับอ็อบเจ็กต์จากพูลที่เรียกว่า free store ตัวดำเนินการใหม่เรียกตัวดำเนินการฟังก์ชันพิเศษใหม่

ตัวดำเนินการใหม่ : หากการร้องขอเป็นศูนย์ไบต์ของพื้นที่จัดเก็บตัวดำเนินการใหม่จะส่งกลับตัวชี้ไปยังวัตถุที่แตกต่างกัน (นั่นคือการเรียกซ้ำไปยังตัวดำเนินการใหม่จะส่งคืนตัวชี้ที่แตกต่างกัน) หากมีหน่วยความจำไม่เพียงพอสำหรับการร้องขอการจัดสรรตัวดำเนินการใหม่จะส่งคืนค่า NULL หรือแสดงข้อยกเว้น อาร์กิวเมนต์แรกสำหรับตัวดำเนินการ new ต้องเป็นประเภท size_t (ประเภทที่กำหนดใน STDDEF.H) และประเภทการส่งคืนจะเป็นโมฆะเสมอ *

นี่คือลิงค์ MSDN สำหรับรายละเอียดเพิ่มเติม:

ตัวดำเนินการฟังก์ชั่นใหม่

ตัวดำเนินการใหม่


1
คำชี้แจงเล็กน้อย: ตัวดำเนินการที่ไม่ใช่ตำแหน่งใหม่จะต้องโยนความล้มเหลวในการจัดสรรเสมอ (ตามมาตรฐาน); และรูปแบบตำแหน่งเช่น::new(std::nothrow)สามารถทำอย่างใดอย่างหนึ่ง (ตัวอย่างนั้นส่งกลับตัวชี้ว่าง)

1
  1. ใหม่เป็นตัวดำเนินการเช่นเดียวกับคำหลัก

    ดู [1] ใน 2.13 && ใน 2.12

  2. ใหม่ทำสองสิ่ง: T * t = ใหม่ T (arg);

    1) จัดสรรหน่วยความจำสำหรับวัตถุ: void * ptr = ตัวดำเนินการใหม่ (sizeof (T));

    // โอเปอเรเตอร์ newเป็นฟังก์ชัน (เช่นเดียวกับ malloc ใน c) ไม่ใช่ตัวดำเนินการ (ดู [1] ใน 3.7.4) แต่รายการที่ 7 [2] บอกว่าเป็นตัวดำเนินการด้วย ในความคิดของฉันความแตกต่างระหว่างตัวดำเนินการและฟังก์ชันนั้นมีขนาดเล็กและคุณสามารถเห็นได้เมื่อคุณจำได้ว่าตัวดำเนินการโอเวอร์โหลดถูกใช้งานโดยฟังก์ชัน

    // เราสามารถโอเวอร์โหลดตัวดำเนินการ / ฟังก์ชั่นนี้ (ตัวดำเนินการใหม่) ทำสิ่งที่เราต้องการได้ที่นี่

    2) เริ่มต้นวัตถุในหน่วยความจำที่จัดสรร: เรียก T :: T (arg) บน ptr

    // คอมไพเลอร์เท่านั้นที่ทำได้ ทั้งฉันและคุณไม่สามารถ

    // คอมไพเลอร์จะเรียกตัวสร้างอ็อบเจ็กต์สมาชิกและคอนสตรัคเตอร์ของคลาสฐานหาก T มี และคำเรียกนี้จะเรียกซ้ำ คอมไพเลอร์เท่านั้นที่สามารถทำได้

  3. ดังนั้นตัวดำเนินการใหม่จึงเป็นส่วนหนึ่งของภารกิจใหม่และเฉพาะในส่วนนี้เท่านั้นที่เราสามารถทำบางสิ่งได้

    [1]: ISO / IEC, N3690 http://ww.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf

    [2]: เมเยอร์สสก็อตต์ C ++ ที่มีประสิทธิภาพ 3

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.