我在理解何時以及是否調用移動構造函數或移動賦值運算符時遇到了一些問題,特別是在具有常數數據成員的類的上下文中。 考慮類使用常數數據成員或引用成員移動類的ctor
template<typename T> class A {
const*T const P ; // constant data member
explicit A(const*T p) : P(p) { std::cerr<<" ctor: P="<<P<<'\n'; }
void test() const { std::cerr" test: P="<<P<<'\n'; }
// move and copy constructors and assignment operators here
};
和測試程序
class B {
int X[100];
A<B> get_a() const { return A<B>(this); }
};
int main() {
B b;
A<B> a = b.get_a(); // which operator/ctor is used for '=' here?
a.test();
}
然後編譯的結果是根據所提供的移動構造函數的定義不同,在A<>
類移動賦值運算符,同時也對編譯器。
沒有(如上)A<>
類的任何進一步聲明,既克++(4.7.0)和ICPC(13.0.1)編譯細(帶有選項-std=c++11
)併產生期望的輸出
ctor: P=0x7fffffffd480
test: P=0x7fffffffd480
如果我聲明
A&A::operator=(A&&) = delete;
A&A::operator=(const A&) = delete;
(這似乎鑑於其必須初始化劑列表初始化常數數據成員的顯),但不提供任何進一步的ctor,使用g ++編譯失敗,但沒關係icichc ic。如果除此之外,我定義(或兩者)
A::A(A&&) = default;
A::A(const A&) = default;
這兩個編譯器都很高興。然而,g ++對組合不滿意
A::A(A&&) = delete;
A::A(const A&) = default;
雖然icpc很高興。
如果我玩同一遊戲中,不同之處在於A::A(A&&) = default;
由
A::A(A&&a) : P(a.P) { std::cerr<<" move ctor: P="<<P<<'\n'; } // never called?
(和等效對於A::A(const A&)
)代替,結果是完全一致的,特別是沒有輸出由這些顯式移動和複製ctors生成。
那麼哪個運營商用於=
在main()
? (以及爲何沒有輸出在最後的測試產生的?)
爲什麼是這樣的操作在這裏允許在所有的,因爲A<>
具有恆定的數據成員(結果是相同的,如果我取代成員const*T const P;
與const T&R
)?
最後,如果有g ++和icpc的不同行爲,如果有的話是正確的?
所以這意味着g ++和icpc在這裏犯了幾個錯誤?特別是,如果所有相關操作都應寫入stderr,我仍然對缺少任何輸出產生困惑。 – Walter
我很確定關於[3]。你可以自己嘗試,代碼是微不足道的。順便說一句,爲什麼析構的存在改變了遊戲? – Walter
因爲,根據Torsten Will的書,析構函數的存在會阻止自動生成移動構造函數。但是,因爲它並不妨礙複製構造函數的生成,所以我不確定實際上是什麼意思。 – JohnB