4

我一直在搞包装在容器类中的引用。为什么下面的代码合法,看起来行为正确?C++引用可以赋值吗?

#include <iostream> 

class Foo 
{ 
public: 
    Foo(int i) : i_(i) {} 
    int i_; 
}; 

class FooWrapper 
{ 
public: 
    FooWrapper(Foo& foo) : foo_(foo) {} 
    Foo& foo_; 
}; 

int main(int argc, char* argv[]) 
{ 
    Foo foo(42); 
    FooWrapper fw(foo); 
    FooWrapper fw2 = fw; 
    std::cout << fw2.foo_.i_ << std::endl; 
    return 0; 
} 

在没有明确的operator=的,我相信C++做一个成员复制。所以当我做FooWrapper fw2 = fw;,这不是两个操作:(1)创建FooWrapper fw与默认ctor后跟(2)分配从fwfw2?我相信这不会发生,因为不能创建未初始化的引用,所以实际上将fw2的创建视为复制构造?

我有时不清楚副本构建与分配的角色;他们似乎有时会流血,就像在这个例子中一样,但可能有一些我不知道的规则。我会很感激一个解释。

回答

3

在下面的线,你正在构建fw2通过使其成为fw的副本。也就是说,您正在调用复制构造函数。

FooWrapper fw2 = fw; 

下面是对如何default constructorcopy constructorcopy assignment operator,和move assignment operator(从C++ 11)被调用的(online)的例子。

#include <iostream> 

struct foo 
{ 
    foo() {std::cout << "Default constructor" << '\n';} 
    foo(foo const&) {std::cout << "Copy constructor" << '\n';} 
    foo& operator=(foo const&) {std::cout << "Copy assignment operator" << '\n'; return *this; } 
    foo& operator=(foo &&) {std::cout << "Move assignment operator" << '\n'; return *this; } 
}; 

int main(int argc, char* argv[]) 
{ 
    foo a;   // Default constructor 
    foo b = a;  // Copy constructor 
    foo c;   // Default constructor 
    c = b;   // Copy assignment operator 
    b = std::move(c); // Move assignment operator 
} 
4

尽管=的语法,FooWrapper fw2 = fw;复制构造fw2(使用复制构造函数)。根本不涉及默认构造和分配。

并回答标题中的问题:否,不能分配参考。如果你写的代码,试图实际上默认构造或分配FooWrapper,如:

FooWrapper fw2; 
fw2 = fw; 

...这会失败。正式的,只需要一个“诊断”。非正式地说,我所知道的每个编译器都会拒绝编译它。

3

该初始化实际上调用了复制构造函数。 FooWrapper fw2 = fw; ,相当于 FooWrapper fw2(fw);

隐含定义拷贝构造函数并不需要创建一个未初始化的参考

参考: http://en.cppreference.com/w/cpp/language/copy_constructor

+0

是的,这就是我的意思。改变了措辞'隐含定义拷贝constructor' –

+0

措词还涉及到这样的事实,时下一个可以显式地请求编译器通过'default'关键字生成一个复制构造: 'CLASS_NAME(常量CLASS_NAME&)=默认值;' –