C++ 为什么没有为我提供来自volatile的默认副本构造函数?

C++ 为什么没有为我提供来自volatile的默认副本构造函数?,c++,copy-constructor,volatile,C++,Copy Constructor,Volatile,此代码: class X { int member; }; volatile X a; X b = a; 失败,错误为: prog.cpp:6:7: error: no matching function for call to ‘X::X(volatile X&)’ prog.cpp:6:7: note: candidates are: prog.cpp:1:7: note: X::X() prog.cpp:1:7: note: candidate expects 0

此代码:

class X {
  int member;  
};

volatile X a;
X b = a;
失败,错误为:

prog.cpp:6:7: error: no matching function for call to ‘X::X(volatile X&)’
prog.cpp:6:7: note: candidates are:
prog.cpp:1:7: note: X::X()
prog.cpp:1:7: note:   candidate expects 0 arguments, 1 provided
prog.cpp:1:7: note: X::X(const X&)
prog.cpp:1:7: note:   no known conversion for argument 1 from ‘volatile X’ to ‘const X&’

有什么方法可以让编译器为我生成一个易失性副本构造函数吗?

关键问题是你没有提供赋值构造函数。因此,编译器会为您生成一个默认值:

X& X::operator =(const X& x){
   this.member = x.member;
   return *this;
}
默认赋值构造函数接受参数类型为const X&,其中const低级const,不会被忽略为顶级const

您的代码
xb=a
意味着调用默认构造函数。但是您的参数
a
具有类型volatile X(可以转换为volatile X&volatile const X&)不能隐式转换为const X&

因此,您应该将自己的赋值构造函数定义为

X& X::operator =(volatile const X&);

编辑
让我震惊的是,这么多人认为在使用赋值运算符时调用了复制构造函数(或调用复制初始化)。 可能称之为赋值运算符并不常见。然而,我关心的是调用哪个方法

你可以参考这篇文章:和


编辑
我以前犯过一个错误。
xb=a
只是一个初始化过程。不涉及任何任务。
为我的错误消息道歉。

简短的回答是:因为标准上说你不会

C++标准128/9(草案N3242)讲述:

类X的隐式声明的复制构造函数的形式为

  • X::X(常数X&)
如果

  • X的每个直接或虚拟基类B都有一个复制构造函数,其第一个参数的类型为const B&或常量挥发性B&和
  • 对于类类型为M(或其数组)的X的所有非静态数据成员,每个此类 类型有一个复制构造函数,其第一个参数的类型为const M&或const volatile M&。[注:119]
否则,隐式声明的复制构造函数将具有

  • X::X(X&)
注119说:

这意味着隐式声明的复制构造函数的引用参数不能绑定到易失性左值; 见C.1.9

在C.1.9中,您会发现:

隐式声明的复制构造函数和隐式声明的复制赋值运算符无法创建 易变左值的副本。例如,以下内容在ISO C中有效:

理由:对几个备选方案进行了详细讨论。将参数更改为volatile const X&将使为类对象生成高效代码变得非常复杂。关于为这些隐式定义的操作提供两个备选签名的讨论引发了未回答的问题,即产生歧义并使根据基和成员指定这些操作符的形成的规则复杂化


但是我想要一个非易失性拷贝
volatile X&
无法转换为
const X&
,因为这两个限定符相互矛盾:
const
表示“读取一次,它不会改变”,而
volatile
表示“每次读取它,因为它可以改变”。必须有一些聪明的规则在C++标准中禁止隐式地进行转换。当然const说“我不会改变它”,而且FAND说其他人可能。我也不同意“<代码> const < /Cord> >说‘读一次,它不会改变’”。
const X&
引用不允许在任何上下文中进行这种优化,因为它对普通的
X&
引用无效。@dasblinkenlight:没有矛盾
const
仅仅防止修改,而
volatile
仅仅意味着读写是可观察的
const volatile
是一个只读变量,其中读取变量是可观察的。否。像
X(volatile const X&X):member(X.member){}
这样的构造函数是必需的,因为
xb=A是复制初始化。没有像“赋值构造函数”这样的东西。有构造函数或赋值运算符。@Pixelchemist您提供的称为“复制构造函数”。这两件事是不同的。它被称为C++中的三规则,三的规则主要应用于管理资源的类。在这种情况下,需要一个非显式复制构造函数来完成从volatile X到X的转换。@Pixelchemist是的。三法则主要适用于有资源的类。作者使用赋值运算符(即=)构造一个新对象。应调用赋值构造函数。不存在“赋值构造函数”。“在C.1.9中你会发现”-这对我来说没有多大意义。C没有复制构造函数。没关系,我刚才注意到你指的是C++标准的附件C。
struct X { int i; };
volatile struct X x1 = {0};
struct X x2(x1); // invalid C++
struct X x3;
x3 = x1; // also invalid C++