constructor copy constructor initialization and assignment operator

摘自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 <SkBitmap::operator=(SkBitmap const&)>
   0x0007377c <+36>: mov r0, r4
   0x00073780 <+40>: pop {r3, r4, r5, pc}
End of assembler dump.

[END]


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误提示意思是没有匹配的构造函数可以进行初始化。这通常是因为你在创建一个对象时,传入的参数类型与该对象的构造函数不匹配。你需要检查一下传入的参数类型是否正确,或者是否需要添加一个新的构造函数来匹配传入的参数类型。 ### 回答2: 当我们使用一个自定义的类创建一个对象,并且在创建对象时出现了"No matching constructor for initialization of"的错误提示,这通常意味着在类的定义中不存在一个与我们使用的参数列表匹配的构造函数。 在 C++ 中,每个类都需要定义至少一个构造函数来初始化其成员变量。构造函数是一种特殊的成员函数,其名称和类名相同,用于创建和初始化类的对象。 当创建一个类的对象时,我们可以使用不同的方式来调用类的构造函数:例如,使用无参构造函数创建一个不进行任何初始化的对象,或者使用包含参数的构造函数创建一个经过初始化的对象。 如果在我们的代码中使用了一个不存在的构造函数,则编译器会提示"No matching constructor for initialization of"的错误信息,因为它无法找到与我们使用的参数列表匹配的构造函数。 解决这个问题的方法通常是添加一个新的构造函数,其中包含适当的参数列表以与我们在创建对象时使用的参数进行匹配。如果不能修改类的定义,则可以使用默认构造函数或者其他已存在的构造函数,并将其参数与我们在创建对象时使用的参数进行匹配。 总之,当出现"No matching constructor for initialization of"的错误提示时,我们需要检查我们的代码,并确保使用的构造函数的参数与类定义中的构造函数匹配,或者添加新的构造函数来解决这个问题。 ### 回答3: “no matching constructor for initialization of”是一种C++编译时错误信息,表示在对象初始化时没有找到匹配的构造函数。 在C++中,类的构造函数是用来初始化类的成员变量的。如果在定义类的对象时,没有给出合适的构造函数参数或者没有定义合适的构造函数,则就会出现“no matching constructor for initialization of”错误。 可能会出现这个错误的原因包括: 1. 提供的构造函数参数与定义的构造函数不匹配:如果定义了一个带有参数的构造函数,但初始化时没有提供需要的参数,或者提供的参数类型不正确,则会出现错误。 2. 没有定义所需的构造函数:如果定义了一个需要特殊参数或特殊初始化的构造函数,而在定义类对象时并没有提供相应的参数,则会出现错误。 例如,以下代码定义了一个类,并且只定义了一个不带参数的构造函数: class MyClass { public: MyClass(); //不带参数的构造函数 int num; }; 如果在定义一个类对象时没有提供参数: MyClass myClassObj; 则会出现“no matching constructor for initialization of MyClass”错误,因为没有提供相应的构造函数参数。 因此,要解决这个错误,需要确定是否存在特殊的构造函数参数或初始化需要,如果有的话,需要定义相应的构造函数;如果没有,则需要提供所需的构造函数参数或更改提供的参数类型以匹配定义的构造函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值