ฉันเดาว่าไม่ แต่ฉันขอยืนยัน จะมีการใช้งานใด ๆconst Foo&&
ที่Foo
เป็นชนิดชั้น?
ฉันเดาว่าไม่ แต่ฉันขอยืนยัน จะมีการใช้งานใด ๆconst Foo&&
ที่Foo
เป็นชนิดชั้น?
คำตอบ:
มีประโยชน์เป็นครั้งคราว C ++ 0x แบบร่างนั้นใช้ในบางที่ตัวอย่างเช่น:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
การโอเวอร์โหลดสองครั้งข้างต้นทำให้มั่นใจได้ว่าฟังก์ชันอื่น ๆref(T&)
และcref(const T&)
ฟังก์ชันไม่ผูกกับค่า rvalues (ซึ่งอาจเป็นไปได้)
อัปเดต
ฉันเพิ่งตรวจสอบมาตรฐานอย่างเป็นทางการN3290ซึ่งน่าเสียดายที่ไม่มีให้ใช้งานแบบสาธารณะและมีอยู่ในวัตถุฟังก์ชัน 20.8 [function.objects] / p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
จากนั้นฉันตรวจสอบร่างโพสต์ C ++ 11 ล่าสุดซึ่งเผยแพร่ต่อสาธารณะN3485และใน 20.8 วัตถุฟังก์ชัน [function.objects] / p2 มันยังคงระบุว่า:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
const T&&
มีการใช้สถานที่อื่น ๆหรือไม่?
const T&&
ป้องกันไม่ให้ใครสักคนโง่ใช้ args ref<const A&>(...)
แม่แบบที่ชัดเจนของรูปแบบ นั่นไม่ใช่ข้อโต้แย้งที่หนักหนาสาหัสนัก แต่ค่าใช้จ่ายที่const T&&
สูงเกินไปT&&
นั้นค่อนข้างน้อย
ความหมายของการได้รับการอ้างอิง const rvalue (ไม่ใช่สำหรับ=delete
) มีไว้สำหรับพูดว่า:
กรณีการใช้งานต่อไปนี้อาจเป็น IMHO กรณีการใช้งานที่ดีสำหรับการอ้างอิง rvalue ไปยัง constแม้ว่าภาษาจะตัดสินใจที่จะไม่ใช้แนวทางนี้ (ดูโพสต์ SO ต้นฉบับ )
โดยปกติจะแนะนำให้ใช้make_unique
และmake_shared
แต่ทั้งสองอย่างunique_ptr
และshared_ptr
สามารถสร้างได้จากตัวชี้ดิบ ตัวสร้างทั้งสองรับตัวชี้ตามค่าและคัดลอก ทั้งสองอนุญาต (กล่าวคือในแง่ของ: อย่าป้องกัน ) การใช้งานต่อเนื่องของตัวชี้เดิมที่ส่งผ่านไปยังพวกเขาในตัวสร้าง
รหัสต่อไปนี้รวบรวมและผลลัพธ์พร้อมฟรีสองเท่า :
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
ทั้งสองอย่างunique_ptr
และshared_ptr
สามารถป้องกันข้างต้นได้หากตัวสร้างที่เกี่ยวข้องคาดว่าจะได้ตัวชี้ดิบเป็นค่า const rเช่นสำหรับunique_ptr
:
unique_ptr(T* const&& p) : ptr{p} {}
ในกรณีนี้โค้ดฟรีสองเท่าด้านบนจะไม่รวบรวม แต่สิ่งต่อไปนี้จะ:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
โปรดทราบว่าptr
ยังสามารถใช้ได้หลังจากย้ายไปแล้วดังนั้นข้อบกพร่องที่อาจเกิดขึ้นจะไม่หายไปทั้งหมด แต่ถ้าผู้ใช้จำเป็นต้องเรียกstd::move
บั๊กดังกล่าวจะตกอยู่ในกฎทั่วไปของ: อย่าใช้ทรัพยากรที่ถูกย้าย
ใครสามารถถาม: ตกลง แต่ทำไมT*
const&& p
?
เหตุผลง่ายๆที่จะช่วยให้การสร้างจากตัวชี้unique_ptr
const โปรดจำไว้ว่าการอ้างอิง const rvalueเป็นทั่วไปมากขึ้นกว่าเพียงแค่การอ้างอิง rvalueขณะที่มันยอมรับทั้งในและconst
non-const
ดังนั้นเราสามารถอนุญาตสิ่งต่อไปนี้:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
สิ่งนี้จะไม่เกิดขึ้นหากเราคาดหวังเพียงการอ้างอิง rvalue (ข้อผิดพลาดในการคอมไพล์: ไม่สามารถผูกconst rvalueกับrvalue ได้ )
อย่างไรก็ตามนี่ก็สายเกินไปที่จะเสนอสิ่งนี้ แต่แนวคิดนี้นำเสนอการใช้การอ้างอิง rvalue กับ constอย่างสมเหตุสมผลconst
พวกเขาได้รับอนุญาตและแม้กระทั่งฟังก์ชันที่ได้รับการจัดอันดับตามconst
แต่เนื่องจากคุณไม่สามารถย้ายจากวัตถุ const ที่อ้างถึงconst Foo&&
ได้จึงไม่มีประโยชน์
const T&, T&, const T&&, T&&
นอกจากstd :: refแล้วไลบรารีมาตรฐานยังใช้การอ้างอิง const rvalue ในstd :: as_constเพื่อวัตถุประสงค์เดียวกัน
template <class T>
void as_const(const T&&) = delete;
นอกจากนี้ยังใช้เป็นค่าส่งคืนในstd :: ทางเลือกเมื่อรับค่าที่รวม:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
เช่นเดียวกับในstd :: get :
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
นี่เป็นที่น่าจะเป็นไปได้เพื่อรักษาหมวดหมู่ของค่าตลอดจนความมั่นคงของ wrapper เมื่อเข้าถึงค่าที่รวมไว้
สิ่งนี้สร้างความแตกต่างว่าสามารถเรียกฟังก์ชันที่มีคุณสมบัติการอ้างอิง const rvalue บนวัตถุที่ห่อหุ้มได้หรือไม่ ที่กล่าวว่าฉันไม่ทราบการใช้งานใด ๆ สำหรับฟังก์ชันที่ผ่านการรับรอง const rvalue ref
ฉันไม่สามารถนึกถึงสถานการณ์ที่สิ่งนี้จะเป็นประโยชน์โดยตรง แต่อาจใช้โดยอ้อม:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
T ในgคือ T const ดังนั้นf 's x จึงเป็น T const &&
เป็นไปได้ว่าสิ่งนี้จะทำให้เกิดข้อผิดพลาด comile ในf (เมื่อพยายามย้ายหรือใช้วัตถุ) แต่fอาจใช้ rvalue-ref เพื่อที่จะไม่สามารถเรียกใช้ lvalues ได้โดยไม่ต้องแก้ไข rvalue (เช่นเดียวกับที่ง่ายเกินไป ตัวอย่างด้านบน)
const&&
มีความสำคัญมากแม้ว่าเขาจะไม่ได้บอกว่าทำไม: youtube.com/watch?v=JhgWFYfdIho#t=54m20s