[英]Is it necessary to block the assignment operator and the copy constructor when using smart pointers?
[英]Is assignment operator always necessary when there is a copy constructor?
我正在學習構造函數和析構函數,並且已經學會了三個規則 。
我現在正在播放tutorialspoint中的一個小例子。 我注意到該示例沒有賦值運算符,但代碼以某種方式運行良好。 例如,對於Line a(b)
,當我改變a中的內容時,例如*(a.ptr),*(b.ptr)不改變。
我還寫了一個賦值運算符(注釋),代碼也可以。
現在我很困惑。 在某些情況下,似乎只有復制構造函數就足夠了。 任何人都可以對此發表評論,以幫助我更好地了解調用復制構造函數所涉及的內存分配機制嗎?
謝謝!
#include <iostream>
using namespace std;
class Line
{
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
void doubleLength(void);
Line &operator=(const Line &);
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int; //simply allocates memory for one integer, and returns a pointer to it.
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
// // copy assignment operator, added by me
// Line& Line::operator=(const Line& that)
// {
// if (this != &that)
// {
// delete ptr;
// // This is a dangerous point in the flow of execution!
// // We have temporarily invalidated the class invariants,
// // and the next statement might throw an exception,
// // leaving the object in an invalid state :(
// this->ptr = new int;
// this->ptr = that.ptr;
// }
// return *this;
// }
Line::~Line(void)
{
cout << "Freeing memory " << ptr << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void Line::doubleLength(void)
{
*ptr = *ptr * 2;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main( )
{
Line line1(10);
// Line line2 = line1; // This also calls copy constructor
Line line2(line1); // performed by copy assignment operator
line2.doubleLength();
display(line1);
display(line2);
return 0;
}
我得到輸出:
Normal constructor allocating ptr
Copy constructor allocating ptr.
Copy constructor allocating ptr.
Length of line : 10
Freeing memory 0x836c028
Copy constructor allocating ptr.
Length of line : 20
Freeing memory 0x836c028
Freeing memory 0x836c018
Freeing memory 0x836c008
Line line2 = line1; //assignment operator but copy constructor will be called implicitly
Line line3(line1); //copy constructor will be called explicitly
從現有對象創建新對象時,將調用復制構造函數。 這里line2
和line3
是從現有的line1
新創建的,所以即使你使用=
也會調用copy構造函數。
Line line2; //default constructor is called
line2 = line1; //assignment operator is called
這里第一行用默認構造函數聲明並初始化它,第二行是賦值。 所以在這里調用賦值運算符。 即,當將對象分配給已初始化的對象時,將調用賦值運算符。
賦值運算符不是必需的,但可能是合乎需要的。
如果你有一個Foo
課,
Foo a; // calls normal constructor
Foo b(a); // calls copy constructor explicitely
Foo c = b; // calls copy constructor (initialization)
b = a; // calls assignment operator
當作為函數調用(值參數)的結果復制對象時,將調用復制構造函數。
以下情況可能導致調用復制構造函數:
這些情況統稱為復制初始化,相當於Obj x = a;
但是,不保證在這些情況下將調用復制構造函數,因為C ++標准允許編譯器在某些情況下優化副本,一個例子是返回值優化(RVO)
術語返回值優化是指C ++標准中的特殊子句,它類似於: 實現可以省略由return語句產生的復制操作,即使復制構造函數具有副作用
RVO特別值得注意的是,允許通過C ++標准更改結果程序的可觀察行為
可以使用以下兩種技術之一為對象分配值:
表達式中的顯式賦值 (調用簡單副本,而不是復制構造函數!)
Object a;
Object b;
a = b;//translates as Object::operator=(const Object&)thus a.operator=(b)is called
初始化 (調用復制構造函數)
可以通過以下任何一種方式初始化對象。
一種。 通過聲明
Object b = a; // translates as Object::Object(const Object&)
灣 通過函數參數
type function(Object a);
C。 通過函數返回值
Object a = function();
當有復制構造函數時,是否總是需要賦值運算符?
復制構造函數僅用於初始化,不適用於使用賦值運算符的賦值。
您的代碼似乎可以正常工作,但有些情況可能會崩潰。 看看你的dtor,它釋放了ptr
指向的內存。 如果將對象分配給另一個對象,則默認賦值運算符將僅復制指針的值(淺拷貝),然后您有兩個對象,每個對象都指向同一個內存塊。 這就是問題。 不禁止這樣做,但是在釋放內存時需要注意等等。當您使用復制ctor獲取深層復制時,您還需要使用賦值運算符來制作相同的深層復制。 這就是為什么存在三個規則(對於所有“復制/分配”場景的對象的統一行為)...
// Line line2 = line1; // This also calls copy constructor
是的,因為僅存在=
字符並不表示調用賦值運算符。 正如cppreference.com所說:
在命名變量的復制初始化中,等號
=
,與賦值運算符無關。 賦值運算符重載對復制初始化沒有影響。
然后在代碼中有以下行:
Line line2(line1); // performed by copy assignment operator
這個評論是錯誤的。 為什么要在這里調用復制賦值運算符?
但是,復制構造函數和復制賦值運算符之間存在一個重要的關系,那就是通常應該使用復制和交換習慣用另一個來實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.