標籤:

拷貝構造函數何時調用?

class bulk_item{
public:
bulk_item(int val):x(val) {}
bulk_item(const bulk_item rhs)
{
cout &<&< "!!!" &<&< endl; x = rhs.x; } private: //bulk_item(const bulk_item ); int x; }; int main(int argc, char const *argv[]) { bulk_item a = bulk_item(10); return 0; }

c++ primer 上明確說在複製初始化時,會調用拷貝構造函數,但是我上面這段代碼執行的時候沒有列印,說明沒有去執行我自定義的拷貝構造函數。不解。。。


以下內容來自C++ Primer Plus第6版(中文版)第12.1.2小節(P.433):

(略)

3.何時調用複製構造函數

新建一個對象並將其初始化為同類現有對象時,複製構造函數都將被調用。這在很多情況下都可能發生,最常見的情況是新對象顯式地初始化為現有的對象。例如,假設motto是一個StringBad對象,則下面4種聲明都將調用複製構造函數:

StringBad ditto(motto);
StringBad metoo = motto;
StringBad also = StringBad(motto);
StringBad * pStringBad = new StringBad(motto);

其中中間的2種聲明可能會使用複製構造函數直接創建metoo和also,也可能使用複製構造函數生成一個臨時對象,然後將臨時對象的內容賦給metoo和also,這取決於具體的實現。最後一種聲明使用motto初始化一個匿名對象,並將新對象的地址賦給pStringBad指針。


若是gcc/clang,加上該編譯器選項 -fno-elide-constructors 即可

--------------------------------------------------------------------------------------------------

看了幾個回答,似乎都沒有弄清楚拷貝構造和賦值操作符,甚至構造函數,我覺得我又要科普一下我的易記法了。

對於拷貝構造來說,歸根結底,落腳點在構造函數上。所以調用拷貝構造的時候,一定是這個對象不存在的時候,如下面這句

bulk_item a = bulk_item(10);

那麼,a是不存在的,而且是通過其它的bulk_item對象構造出來的,那麼則調用的是拷貝構造函數。

如果是

bulk_item a(1);
a = bulk_item(10);

那麼這裡就調用的是賦值操作符,因為a是已經存在的對象了,不需要構造了。

至於下面回答調用構造函數的,就純屬亂說的範圍了,雖然在構造函數裡面有輸出信息,然後列印出來了,但是這個構造函數是bulk_item(10)調用然後列印出來的。


標準里說了在拷貝初始化中,拷貝構造函數可以被省略掉。不過雖然可被省略,但拷貝構造函數對這個語句確實有影響,比如說如果拷貝構造函數是私有的,那麼這個語句就是非法的。

所以這裡應該是被優化為了構造函數,而不調用拷貝構造函數。

#include &
using namespace std;
class bulk_item{
public:
bulk_item(int val):x(val)
{
cout&<&<"ctr"&<&

會輸出ctr。

實驗的時候把拷貝構造聲明為private會導致編譯失敗,同時如果加入一個private的移動構造函數也會導致編譯失敗。。。。。。。。


然而這裡的copy-init被非常正常地優化掉了。直接用10初始化a。

8.5

(17.6.2) - ... In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8.

12.8確實還有一點。。

(31.3) - when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unquali?ed type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

找的好像不對,不管了。


bulk_item a = bulk_item(10);
//你這確實沒拷貝啊。。標準的初始化方式,
//這編譯器應該直接調構造函數搞定啊

bulk_item b = a; //這樣再來一下就是拷貝了


推薦閱讀:

什麼是tlsf內存分配演算法? 它和普通的內存分配演算法有什麼區別?
C++派生類的成員或友員只能通過派生類對象來訪問基類的受保護成員?
變數名儲存在那裡,變數的儲存機制是什麼?
編程中你們都習慣怎麼使用大括弧?
C++中char是如何在地址中存儲的?

TAG:C |