摘自C++ ARM的一段
Objects of classes with constructors can be initialized with a parenthesized expression list.
This list is taken as the argument list for a call of a constructor doing the initialization.
Alternatively a single value is specified as the initializer using the = operator. This value is used as the argument to a copy constructor.
Typically, that call of a copy constructor can be eliminated.
Overloading of the assignment operator has no effect on initialization.
Specifying initialization using = as normal expression evaluation followed by a copy operation (that is usually optimized away) has three effects:
- The set of values acceptable for initialization and assignment will be identical except where the user specifically defines constructors and /or assignment operators to ensure that they are not.
- Access control is applied for the copy constructor (just as it is for assignment).
- The use of a temporary and its possible elimination are explicitly allowed, giving implementers a degree of freedom that is sometimes needed.
Note that initialization and assignment are generally very different operations.
Initialization occurs wherever an object is created.
Assignment occurs when an assignment operator is used in an expression. An assignment operation will always invoke a predefined, user-defined, or default assignment operator. The left operand of an assignment is always a previously constructed object, whereas an object being initialized never is. Assignment operations typically rely on being invoked only for fully constructed objects.
Android Skia Bitmap中的一段代码
SkBitmap::SkBitmap() {
sk_bzero(this, sizeof(*this));
}
SkBitmap::SkBitmap(const SkBitmap& src) {
SkDEBUGCODE(src.validate();)
sk_bzero(this, sizeof(*this));
*this = src;
SkDEBUGCODE(this->validate();)
}
SkBitmap::~SkBitmap() {
SkDEBUGCODE(this->validate();)
this->freePixels();
}
SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
if (this != &src) {
this->freePixels();
memcpy(this, &src, sizeof(src));
// inc src reference counts
SkSafeRef(src.fPixelRef);
SkSafeRef(src.fMipMap);
// we reset our locks if we get blown away
fPixelLockCount = 0;
/* The src could be in 3 states
1. no pixelref, in which case we just copy/ref the pixels/ctable
2. unlocked pixelref, pixels/ctable should be null
3. locked pixelref, we should lock the ref again ourselves
*/
if (NULL == fPixelRef) {
// leave fPixels as it is
SkSafeRef(fColorTable); // ref the user's ctable if present
} else { // we have a pixelref, so pixels/ctable reflect it
// ignore the values from the memcpy
fPixels = NULL;
fColorTable = NULL;
// Note that what to for genID is somewhat arbitrary. We have no
// way to track changes to raw pixels across multiple SkBitmaps.
// Would benefit from an SkRawPixelRef type created by
// setPixels.
// Just leave the memcpy'ed one but they'll get out of sync
// as soon either is modified.
}
}
SkDEBUGCODE(this->validate();)
return *this;
}
Copy constructor SkBitmap::SkBitmap(const SkBitmap& src)中使用了operator assignment,红色的代码*this = arc,但是此时this仍是还没有fully constructed的对象,根据上面的段落 The left operand of an assignment is always a previously constructed object, whereas an object being initialized never is. Assignment operations typically rely on being invoked only for fully constructed objects. 那么调用的不是user-defined operator assignment?这样理解是一个误区。虽然是在拷贝构造函数中,但是*this = src语法上针对了fully constructed object的,编译器还没有智能到知道这个语句是在拷贝构造函数中使用,this是一个还未完全构造完毕的对象,所以*this = src in copy constructor仍然是调用的user-defined operator assignment。
拷贝构造函数编译出的指令如下,可以看到operator assignment的调用;
(gdb) disass 'SkBitmap::SkBitmap(SkBitmap const&)'
Dump of assembler code for function SkBitmap::SkBitmap(SkBitmap const&):
0x00073758 <+0>: push {r3, r4, r5, lr}
0x0007375c <+4>: mov r2, #40 ; 0x28
0x00073760 <+8>: mov r4, r0
0x00073764 <+12>: mov r5, r1
0x00073768 <+16>: mov r1, #0
0x0007376c <+20>: bl 0x68e58
0x00073770 <+24>: mov r0, r4
0x00073774 <+28>: mov r1, r5
0x00073778 <+32>: bl 0x73684
0x0007377c <+36>: mov r0, r4
0x00073780 <+40>: pop {r3, r4, r5, pc}
End of assembler dump.
[END]