Skip to content

构造函数 #2

@chlict

Description

@chlict

右值:
字面量(如10, 'a')和临时对象(如A())

"区分左值和右值的一个简单办法是:看能不能对表达式取地址,如果能,则为左值,否则为右值。"

const A& 和A&& 都会引用到临时对象,但是A&&的优先级更高

auto a = A();不会调用copy/move constructor,只会调用普通的constructor,实际上就是在栈上分配一块空间,执行构造函数,只有一个对象,等价于A a();
而a = A();(a是一个已有对象)会调用copy/move assignment,因为存在两个对象:先构造一个临时对象A(),再赋值给a,如果A有move assignment,则优先调用move assignment

值得注意的是,foo_by_value(A())不会调用copy/move constructor,仍然是栈上构造一个对象,类似auto a = A();
foo_by_value(a)永远会调用copy constructor
foo_by_ref(A()),foo_by_ref(const A&)和foo_by_ref(A&&)都合法,两者都存在时优先匹配A&&

对于返回值是struct的函数,编译器有return slot优化,直接在父函数的栈帧上构造对象,而不是现在本函数构造对象,再拷贝给父函数,编译器会把父函数栈帧上return slot的地址传给本函数
auto a = foo() {return A();} 不会调用copy/move constructor,直接在父函数栈帧上用A()构造a
A a = foo() { return A(); }同上
a = foo() { return A(); },现在父函数上构造一个临时对象,然后copy/move assignment给a

a5 = f4(): Copy constructor? -- no
Constructing 0x7fffdb9e7ec0 with parm 5
[Enter f4]:
-- outside
Move assignment: &other = 0x7fffdb9e7ec0, other.a = 5, this = 0x7fffdb9e7ea8, this->a = 5

重点区分:
auto a = A();
auto a = foo() { return A(); }
都不会调copy constructor,只有一次default constructing

foo_by_value(A());
foo_by_value(a);
一个不调copy constructor,一个要调

注:以上结果是g++/clang++默认对构造函数优化的结果,如果加了-fno-elide-constructors,结果会很不一样

那么move constructor的意义是什么?
copy constructor一般是深拷贝,保证两个对象各自拥有独立的资源。而如果src对象是个临时对象,不需要有独立资源时,用move constructor做浅拷贝就好了:
auto a = foo() { return A(); } 或 A a = foo() { return A(); }

move assignment适用场景:
a = A();
a = foo() { return A(); }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions