我有一個構造新對象的工廠類。 新對象應該不被複制,但可能被移動。所以我想我會刪除複製構造函數和複製賦值運算符,同時提供移動構造函數和移動賦值運算符。指定右值作爲返回值時出現分段錯誤
我認爲,爲了幫助傳達對象必須移動到而不是複製的想法,我會返回一個右值引用。但是,在這樣做的時候,編譯器似乎總是生成代碼,這些代碼會破壞返回的「到期」對象,然後向移動構造函數或移動賦值運算符提供同一個(銷燬!)對象。
所以我想知道;我有違規的標準嗎?如果是這樣,是否有警告(錯誤,最好是)我可以阻止我繼續做這麼愚蠢的事情?否則,如果我沒有違反任何標準,那麼我認爲這是一個編譯器錯誤?
// g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
// g++ test.cpp -std=c++11
#include <iostream>
#include <memory>
struct PTR {
char * blah = nullptr;
PTR(char* blah) : blah(blah)
{
std::cout << "\tctor @" << (void*)this << std::endl;
}
PTR(const PTR & copy_ctor) : blah(new char)
{
*blah = *copy_ctor.blah;
std::cout << "\tcopy @@" << (void*)this << "\t<-" << (void*)©_ctor << std::endl;
}
PTR(PTR && move_ctor) : blah(move_ctor.blah)
{
move_ctor.blah = nullptr;
std::cout << "\tctor&&@" << (void*)this << "\t<@" << (void*)&move_ctor << std::endl;
}
PTR & operator=(const PTR & copy_assign)
{ delete blah;
blah = new char;
*blah = *copy_assign.blah;
std::cout << "[email protected]" << (void*)this << "\t<-" << (void*)©_assign << std::endl;
return *this;
}
PTR & operator=(PTR && move_assign)
{
delete blah;
blah = move_assign.blah;
move_assign.blah = nullptr;
std::cout << "\tmove&&@" << (void*)this << "\t<@" << (void*)&move_assign << std::endl;
return *this;
}
~PTR()
{
std::cout << "\[email protected]" << (void*)this << std::endl;
delete blah;
}
};
PTR make_ptr_l() {
PTR ptr(new char());
return std::move(ptr); // Without std::move, compiler *may* opt to copy the class, which is undesired
}
PTR && make_ptr_r() {
PTR ptr(new char());
return std::move(ptr); // Requires std::move to turn ptr into rvalue, otherwise compiler error
}
int main() {
std::cout << "lvalue: \n" << std::flush;
PTR ptr = make_ptr_l();
std::cout << "successful\nrvalue new: \n" << std::flush;
{
PTR ptr_r = make_ptr_r();
std::cout << "successful\nrvalue assign: \n" << std::flush;
}
ptr = make_ptr_r();
std::cout << "successful" << std::endl;
return 0;
}
與上面的代碼中,可以看到以下輸出:
lvalue:
ctor @0x7ffed71b7a00
ctor&&@0x7ffed71b7a30 <@0x7ffed71b7a00
[email protected]
successful
rvalue new:
ctor @0x7ffed71b7a00
[email protected]
ctor&&@0x7ffed71b7a40 <@0x7ffed71b7a00
successful
rvalue assign:
[email protected]
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001d1bc40 ***
Aborted (core dumped)
正如你可以rvalue new
後看到,一個對象被構造,然後立即銷燬,則銷燬對象被傳遞給一個移動構造函數。因爲移動構造函數因此訪問被破壞的變量,所以這是分段錯誤的根源。
我已經用g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
以及Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
試過了。
'make_ptr_r'返回對局部變量的引用。當函數退出時變量消失,並且參考變得懸空。任何嘗試實際使用此參考文獻都會顯示未定義的行爲。這是一個右值引用的事實不會改變任何東西。 –
要添加到@IgorTandetnik所說的內容中:'make_ptr_r'的返回類型應該是'PTR',而不是'&&'。檢查你的代碼的輸出,看看它對你有意義。 –
@DanielFrey我沒有檢查輸出,甚至提到它沒有太大意義。我誤解了std :: move()和返回類型的右值引用應該將對象移出本地的想法。 – inetknght