ส่งคืนวัตถุ“ NULL” หากไม่พบผลการค้นหา


95

ฉันค่อนข้างใหม่กับ C ++ ดังนั้นฉันจึงมักจะออกแบบด้วย Java-isms จำนวนมากในขณะที่ฉันเรียนรู้ อย่างไรก็ตามใน Java ถ้าผมมีระดับด้วย 'ค้นหา' วิธีการที่จะกลับวัตถุTจากที่ตรงกับพารามิเตอร์ที่เฉพาะเจาะจงที่ผมจะกลับมาที่และวัตถุถ้าวัตถุไม่พบในคอลเลกชันที่ฉันจะกลับมาCollection< T > nullจากนั้นในฟังก์ชันการโทรของฉันฉันจะตรวจสอบif(tResult != null) { ... }

ใน C ++ ฉันพบว่าฉันไม่สามารถคืนnullค่าได้หากไม่มีวัตถุ ฉันแค่ต้องการส่งคืน 'ตัวบ่งชี้' ประเภท T ที่แจ้งฟังก์ชันการโทรว่าไม่พบวัตถุ ฉันไม่ต้องการโยนข้อยกเว้นเพราะมันไม่ใช่สถานการณ์พิเศษจริงๆ

นี่คือลักษณะของรหัสของฉันในตอนนี้:

class Node {
    Attr& getAttribute(const string& attribute_name) const {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return NULL; // what should this be?
    }

private:
    vector<Attr> attributes;
}

ฉันจะเปลี่ยนได้อย่างไรจึงจะให้เครื่องหมายแบบนั้นได้


6
ข้อยกเว้นและ NULL ไม่ใช่ทางออกเดียวเสมอไป คุณมักจะสามารถเลือกค่าที่จะส่งคืนโดยระบุว่าไม่พบเช่นstd::find(first, last, value)ส่งคืนlastหากไม่มีองค์ประกอบที่ตรงกัน
Cascabel

คำตอบ:


72

ใน C ++ การอ้างอิงต้องไม่เป็นโมฆะ หากคุณต้องการส่งคืนค่าว่างเป็นทางเลือกหากไม่พบสิ่งใดคุณต้องส่งคืนตัวชี้ไม่ใช่ข้อมูลอ้างอิง:

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return nullptr;
}

มิฉะนั้นหากคุณยืนยันที่จะส่งคืนโดยการอ้างอิงคุณควรโยนข้อยกเว้นหากไม่พบแอตทริบิวต์

(อย่างไรก็ตามฉันกังวลเล็กน้อยเกี่ยวกับวิธีการของคุณconstและส่งคืนconstแอตทริบิวต์ที่ไม่ใช่แอตทริบิวต์ด้วยเหตุผลทางปรัชญาฉันขอแนะนำให้กลับมาconst Attr *หากคุณอาจต้องการแก้ไขแอตทริบิวต์นี้ด้วยคุณสามารถโอเวอร์โหลดด้วยconstวิธีที่ไม่ใช่คืนค่าที่ไม่ใช่constแอตทริบิวต์ด้วย)


2
ขอบคุณ. อย่างไรก็ตามนี่เป็นวิธีที่ได้รับการยอมรับในการออกแบบกิจวัตรดังกล่าวหรือไม่?
aduric

6
@aduric: ใช่ การอ้างอิงเป็นนัยว่าผลลัพธ์จะต้องมีอยู่จริง ตัวชี้บ่งบอกว่าผลลัพธ์อาจไม่มีอยู่จริง
บิล

7
แค่อยากรู้เราจะกลับมาnullptrแทนที่จะNULLเป็น c ++ 11 ตอนนี้หรือไม่
Spectral

1
ใช่ใช้ nullptr เหนือ NULL ใน C ++ 11 และใหม่กว่าเสมอ หากคุณต้องการใช้งานร่วมกับ earliver เวอร์ชันย้อนหลังก็ไม่ควรทำ
Conrad Jones

56

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

  • ส่งคืนโดยการอ้างอิงและสัญญาณไม่พบโดยข้อยกเว้น

    Attr& getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            throw no_such_attribute_error;
    }

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

  • กลับตามตัวชี้

    Attr* getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return &attributes[i];
       //if not found
            return nullptr;
    }

ง่ายที่จะลืมตรวจสอบว่าผลลัพธ์จาก getAttribute เป็นตัวชี้ที่ไม่ใช่ NULL หรือไม่และเป็นแหล่งที่มาของจุดบกพร่องได้ง่าย

  • ใช้Boost

    boost::optional<Attr&> getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return boost::optional<Attr&>();
    }

การเพิ่ม :: ทางเลือกหมายถึงสิ่งที่เกิดขึ้นที่นี่และมีวิธีง่ายๆในการตรวจสอบว่าพบแอตทริบิวต์ดังกล่าวหรือไม่


หมายเหตุด้านข้าง: std :: optional ได้รับการโหวตให้เป็น C ++ 17 เมื่อเร็ว ๆ นี้ดังนั้นนี่จะเป็น "มาตรฐาน" ในอนาคตอันใกล้


+1 ฉันจะพูดถึงการเพิ่ม :: ทางเลือกก่อนและจะกล่าวถึงทางเลือกอื่น ๆ สั้น ๆ เท่านั้น
Nemanja Trifunovic

ฉันเห็นการเพิ่ม :: ทางเลือกที่กล่าวถึงที่ไหนสักแห่ง แต่ฉันคิดว่ามันต้องใช้ค่าใช้จ่ายมากเกินไป หากใช้เป็นแนวทางที่ดีที่สุดสำหรับปัญหาประเภทนี้ฉันจะเริ่มใช้มัน
aduric

boost::optionalไม่เกี่ยวข้องกับค่าใช้จ่ายมากนัก (ไม่มีการจัดสรรแบบไดนามิก) ซึ่งเป็นเหตุผลว่าทำไมจึงยอดเยี่ยม การใช้มันกับค่า polymorphic ต้องใช้การอ้างอิงหรือตัวชี้แบบตัด
Matthieu M.

2
@MatthieuM. มีแนวโน้มว่า aduric เหนือศีรษะที่อ้างถึงนั้นไม่ใช่ประสิทธิภาพ แต่เป็นค่าใช้จ่ายในการรวมไลบรารีภายนอกเข้าในโครงการ
Swoogan

ภาคผนวกสำหรับคำตอบของฉัน: โปรดทราบว่ามีการเคลื่อนไหวเกิดขึ้นเพื่อสร้างมาตรฐานทางเลือกให้เป็นส่วนประกอบมาตรฐานซึ่งอาจเป็น C ++ 17 ดังนั้นจึงควรรู้เกี่ยวกับเทคนิคนี้
Kaz Dragon

22

คุณสามารถสร้างวัตถุคงที่ซึ่งแสดงถึงผลตอบแทน NULL ได้อย่างง่ายดาย

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

และบางแห่งในไฟล์ต้นฉบับ:

static Attr AttrNull;

NodeNull ไม่ควรเป็นประเภท Attr?
aduric

3

หากคุณต้องการNULLผลตอบแทนคุณต้องใช้พอยน์เตอร์แทนการอ้างอิง

NULLอ้างอิงตัวเองไม่สามารถ

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

ดูคำตอบของฉันที่นี่สำหรับรายชื่อของความแตกต่างระหว่างการอ้างอิงและตัวชี้


2

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

typedef std::map<string, Operator> OPERATORS_MAP;

bool OperatorList::tryGetOperator(string token, Operator& op)
{
    bool val = false;

    OPERATORS_MAP::iterator it = m_operators.find(token);
    if (it != m_operators.end())
    {
        op = it->second;
        val = true;
    }
    return val;
}

ฟังก์ชันข้างต้นจะต้องค้นหาตัวดำเนินการเทียบกับคีย์ 'โทเค็น' หากพบว่าฟังก์ชันจะส่งคืนจริงและกำหนดค่าให้กับพารามิเตอร์ Operator & op

รหัสผู้โทรสำหรับรูทีนนี้มีลักษณะดังนี้

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}

1

เหตุผลที่คุณไม่สามารถกลับ NULL Attr&นี่เป็นเพราะคุณได้ประกาศประเภทกลับของคุณเป็น การต่อท้าย&ทำให้ค่าส่งคืนเป็น "การอ้างอิง" ซึ่งโดยพื้นฐานแล้วเป็นตัวชี้ที่รับประกันว่าจะไม่เป็นค่าว่างสำหรับวัตถุที่มีอยู่ หากคุณต้องการที่จะสามารถที่จะกลับ null เปลี่ยนแปลงไปAttr&Attr*


0

คุณไม่สามารถคืนค่าได้NULLเนื่องจากประเภทการส่งคืนของฟังก์ชันเป็นวัตถุreferenceไม่ใช่ a pointer.


-3

คุณสามารถลองสิ่งนี้:

return &Type();

6
แม้ว่าข้อมูลโค้ดนี้จะช่วยแก้ปัญหาได้ แต่การมีคำอธิบายจะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้มาก โปรดจำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและบุคคลเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำโค้ดของคุณ
NathanOliver

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