C++ 引用可以赋值吗?
C++ reference can be assignable?
我一直在处理包装在容器 类 中的引用。为什么以下代码是合法的并且表现得正确?
#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
,然后是 (2) 从 fw
到 fw2
的赋值?我确定这不会发生,因为无法创建未初始化的引用,因此 fw2
的创建实际上是否被视为复制构造?
我有时不清楚复制构造与赋值的作用;它们有时似乎会相互渗透,就像这个例子一样,但可能有一些我不知道的规则。我将不胜感激。
尽管语法中有 =
,FooWrapper fw2 = fw;
复制构造 fw2
(使用复制构造函数)。根本不涉及默认构造和赋值。
并回答标题中的问题:不,无法分配引用。如果您编写的代码试图实际默认构造或分配 FooWrapper
,例如:
FooWrapper fw2;
fw2 = fw;
...这会失败。正式地,只需要 "diagnostic"。非正式地,我知道的每个编译器 would/will 都拒绝编译它。
这个初始化实际上调用了拷贝构造函数。
FooWrapper fw2 = fw;
并且相当于
FooWrapper fw2(fw);
隐式定义的复制构造函数不需要创建未初始化的引用
供参考:
http://en.cppreference.com/w/cpp/language/copy_constructor
在下面的行中,您通过复制 fw
来构建 fw2
。也就是说,您正在调用复制构造函数。
FooWrapper fw2 = fw;
例子
这里调用了一个 (online) example on how default constructor, copy constructor, copy assignment operator, and move assignment operator (来自 C++11)。
#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
}
我一直在处理包装在容器 类 中的引用。为什么以下代码是合法的并且表现得正确?
#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
,然后是 (2) 从 fw
到 fw2
的赋值?我确定这不会发生,因为无法创建未初始化的引用,因此 fw2
的创建实际上是否被视为复制构造?
我有时不清楚复制构造与赋值的作用;它们有时似乎会相互渗透,就像这个例子一样,但可能有一些我不知道的规则。我将不胜感激。
尽管语法中有 =
,FooWrapper fw2 = fw;
复制构造 fw2
(使用复制构造函数)。根本不涉及默认构造和赋值。
并回答标题中的问题:不,无法分配引用。如果您编写的代码试图实际默认构造或分配 FooWrapper
,例如:
FooWrapper fw2;
fw2 = fw;
...这会失败。正式地,只需要 "diagnostic"。非正式地,我知道的每个编译器 would/will 都拒绝编译它。
这个初始化实际上调用了拷贝构造函数。
FooWrapper fw2 = fw;
并且相当于
FooWrapper fw2(fw);
隐式定义的复制构造函数不需要创建未初始化的引用
供参考: http://en.cppreference.com/w/cpp/language/copy_constructor
在下面的行中,您通过复制 fw
来构建 fw2
。也就是说,您正在调用复制构造函数。
FooWrapper fw2 = fw;
例子
这里调用了一个 (online) example on how default constructor, copy constructor, copy assignment operator, and move assignment operator (来自 C++11)。
#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
}