[英]RVO/NRVO and public undefined copy constructor
我現在正在與下面的提案作斗爭,我想知道合法的,在較小程度上反對它的道德論點。
我們有什么:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*something non-trivial: say, calls delete for all elements in v*/ }
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C(C const &);
C& operator=(C const&);
private:
std::vector< T* > v;
};
void init(C& c) { } // cannot be moved inside C
// ...
int main()
{
// bad: two-phase initialization exposed to the clients
C c;
init(c);
// bad: here follows a lot of code that only wants read-only access to c
// but c cannot be declared const
}
提出了什么:
#include <vector>
class T;
class C
{
public:
C() { }
~C( ) { /*calls delete for all elements in v*/ }
// MADE PUBLIC
C(C const &); // <-- NOT DEFINED
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C& operator=(C const&);
private:
vector< T* > v;
};
C init() // for whatever reason object CANNOT be allocated in free memory
{
C c;
// init c
return c;
}
// ...
int main()
{
C const & c = init();
}
這使用最新的g ++(這是唯一的目標編譯器)編譯和鏈接(並且工作)4.1.2和4.4.5 - 因為(N)RVO,從不調用復制構造函數; 析構函數僅在main()的末尾調用。
聲稱該技術非常好,因為復制構造函數無法被誤用(如果它曾經生成它將是鏈接器錯誤),並且公開它會阻止編譯器抱怨私有。
對我來說,使用這樣的技巧看起來真的非常錯誤,我覺得這與C ++精神相矛盾,而且看起來更像是黑客 - 在這個詞的不好意義上。
我的感受並不充分,所以我現在正在尋找技術細節。
請不要在這里發布教科書C ++的東西:
vector<shared_ptr<T> >
也不能使用ptr_vector<T>
; C
並通過C*
從init
返回它。 謝謝。
這使用最新的g ++(這是唯一的目標編譯器)編譯和鏈接(並且工作)4.1.2和4.4.5 - 因為(N)RVO,從不調用復制構造函數; 析構函數僅在main()的末尾調用。
雖然它可能適用於GCC,但您的代碼確實具有未定義的行為,因為它引用了未定義的函數。 在這種情況下,你的程序是不正確的; 無需診斷。 這意味着GCC可能會忽略規則違規,但其他編譯器可能會診斷它或做其他奇怪的事情。
所以基於這些理由,我會拒絕這種方式。
我的感受並不充分,所以我現在正在尋找技術細節。
你想在這里移動語義。 有這個明確的呢?
class T;
class C;
struct CMover {
C *c;
private:
CMover(C *c):c(c) { }
friend CMover move(C &c);
};
class C {
public:
C() { }
~C( ) { /*calls delete for all elements in v*/ }
C(CMover cmove) {
swap(v, cmove.c->v);
}
inline operator CMover();
// a lot of member functions that modify C
// a lot of member functions that don't modify C
private:
C& operator=(C const&); // not copy assignable
C(C &); // not lvalue copy-constructible
private:
vector< T* > v;
};
CMover move(C &c) { return CMover(&c); }
C::operator CMover() { return move(*this); }
現在你可以說
C init() // for whatever reason object CANNOT be allocated in free memory
{
C c;
return move(c);
}
int main() {
C const c(init());
}
顯而易見的答案是編譯器沒有義務忽略復制結構,特別是如果禁用優化(盡管即使沒有優化,g ++仍然會使副本省略)。 因此,您限制了可移植性。
最有可能的是,如果它在特定編譯器上編譯,它將按預期運行。
我知道你可以做的事情有很多看似隨意/人為的限制,但你能用C
代理持有人嗎?
class C
{
private:
C() { }
~C( ) { /*calls delete for all elements in v*/ }
// ...
friend class C_Proxy;
};
class C_Proxy
{
public:
C_Proxy() : c_() { init(c_); }
// Or create a public const& attribute to point to this.
const C& get_C() const { return c_; }
private:
C c_;
};
這看起來像是你不會僅僅因為技術原因而從人們頭腦中得到的東西(又名“但它編譯並適用於我們的編譯器!”),所以也許概念上更簡單的方法可能是一個好主意?
如果你關心的是常量......
C c; init(c); // bad: here follows a lot of code that only wants read-only access to c // but c cannot be declared const
與
C const & c = init();
最簡單的(如:無需黑客和代理服務器)解決方案可能是:
C c_mutable_object;
init(c_mutable_object);
C const& c = c_mutable_object;
// ... lots of code with read-only access to c
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.