gpt4 book ai didi

c++ - 在引用初始化中使用已删除的复制构造函数进行复制初始化

转载 作者:行者123 更新时间:2023-12-01 09:02:31 26 4
gpt4 key购买 nike

考虑以下代码:

#include <iostream>
class Data{
public:
Data() = default;
Data(Data const&) = delete;
Data(int) {

}
};
int main(){
int a = 0;
const std::string& rs = "abc"; // rs refers to temporary copy-initialized from char array
Data const& d_rf = a; // #2 but here can be complied
// accroding to the standard, the reference in #2 is bound to a temporary object, the temporary is copy-initialized from the expression
}

[dcl.init.ref]

If T1 or T2 is a class type and T1 is not reference-related to T2, user-defined conversions are considered using the rules for copy-initialization of an object of type “cv1 T1” by user-defined conversion ([dcl.init], [over.match.copy], [over.match.conv]); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference. For this direct-initialization, user-defined conversions are not considered



Copy initialization

Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversions that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in [over.match.copy], and the best one is chosen through overload resolution ([over.match]). If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The function selected is called with the initializer expression as its argument; if the function is a constructor, the call is a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor. The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.



按照标准, a的类型为 int,而初始化引用的类型为 Data,因此从 intData,使用复制类型为“cv1 T1”类型的对象的初始化规则,考虑了 用户定义的转换。 ”由用户定义的转换。这意味着 Data const& d_rf = a;可以转换为 Data temporary = a; Data const& d_rf = temporary;。对于 Data temporary = a;,即使存在 复制省略,也必须检查 复制/移动构造函数是否可用,但是 class Data复制构造函数被删除了,为什么要遵守?

这是一些标准的报价
Copy initialization of reference来自裁判

来自cppreference的 Copy initialization of reference

If the reference is an lvalue reference:

If object is an lvalue expression, and its type is T or derived from T, and is equally or less cv-qualified, then the reference is bound to the object identified by the lvalue or to its base class subobject.
If object is an lvalue expression, and its type is implicitly convertible to a type that is either T or derived from T, equally or less cv-qualified, then the non-explicit conversion functions of the source type and its base classes that return lvalue references are considered and the best one is selected by overload resolution. The reference is then bound to the object identified by the lvalue returned by the conversion function (or to its base class subobject)

Otherwise, if the reference is either rvalue reference or lvalue reference to const:

If object is an xvalue, a class prvalue, an array prvalue, or a function lvalue type that is either T or derived from T, equally or less cv-qualified, then the reference is bound to the value of the initializer expression or to its base subobject.
If object is a class type expression that can be implicitly converted to an xvalue, a class prvalue, or a function value of type that is either T or derived from T, equally or less cv-qualified, then the reference is bound to the result of the conversion or to its base subobject.
Otherwise, a temporary of type T is constructed and copy-initialized from object. The reference is then bound to this temporary. Copy-initialization rules apply (explicit constructors are not considered).
[example:
const std::string& rs = "abc"; // rs refers to temporary copy-initialized from char array ]



更新:

我们考虑 N337下的代码

根据标准,值 a的类型为 int,引用所引用的目标类型为 Data,因此编译器需要通过 复制初始化来生成 Data类型的临时值。毫无疑问,这里我们专注于 复制初始化。源类型为 int,目标类型为 Data,这种情况符合:

Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3). If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified version of the destination type. The temporary is a prvalue. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized;



注意粗体部分,并不意味着 int值通过 Data::Data(int)直接初始化临时项。这意味着,首先将 intData转换为 Data::Data(int),然后此结果将直接初始化临时对象 ,该临时对象是此处为复制初始化的目标的对象。如果我们使用代码来表示粗体部分,则类似于 Data temporary(Data(a))

上面的规则在这里:

— If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.



请重新返回 Data temporary(Data(a))。显然,复制/移动构造函数是参数Data(a)的最佳匹配。但是, Data(Data const&) = delete;,因此复制/移动构造函数不可用。为什么编译器不报告错误?

最佳答案

Issue 1604解决了该问题,建议的解决方案似乎可以确认此类代码格式错误,因此我将其视为编译器错误。

幸运的是,从C++ 17开始,此代码成为格式正确的because of guaranteed copy elision,与编译器一致。

关于c++ - 在引用初始化中使用已删除的复制构造函数进行复制初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59820118/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com