Mar*_*ork 11 c++ copy-constructor
以下代码仅在复制构造函数可用时有效.
当我添加print语句(via std::cout)并使复制构造函数可用时,它不会被使用(我假设有这样的编译器技巧,以删除不必要的副本).
但是在输出operator <<和plop()下面的函数(我创建一个临时对象)中我都没有看到复制构造函数的需要.当我通过const引用(或者我做错了)传递所有内容时,有人可以解释为什么语言需要它.
#include <iostream>
class N
{
public:
N(int) {}
private:
N(N const&);
};
std::ostream& operator<<(std::ostream& str,N const& data)
{
return str << "N\n";
}
void plop(std::ostream& str,N const& data)
{
str << "N\n";
}
int main()
{
std::cout << N(1); // Needs copy constructor (line 25)
plop(std::cout,N(1)); // Needs copy constructor
N a(5);
std::cout << a;
plop(std::cout,a);
}
Run Code Online (Sandbox Code Playgroud)
编译:
[Alpha:〜/ X] myork%g ++ -v
使用内置规格.
目标:i686-apple-darwin10
配置:/ var/tmp/gcc/gcc-5646~6/src/configure --disable-checking --enable-werror --prefix =/usr --mandir =/share/man --enable-languages = c,objc,c ++,obj-c ++ --program-transform-name =/^ [cg] [^ .-]*$/s/$/ - 4.2/--with-slibdir =/usr/lib --build = i686-apple-darwin10 --with-gxx-include-dir =/include/c ++/4.2.1 --program-prefix = i686-apple-darwin10- --host = x86_64-apple- darwin10 --target = i686-apple-darwin10
线程模型:posix
gcc版本4.2.1(Apple Inc. build 5646)[Alpha:〜/ X] myork%g ++ t.cpp
t.cpp:在函数'int main()'中:
t.cpp:10:错误:'N :: N(const N&)'是私有的
t.cpp: 25:错误:在此上下文中
t.cpp:10:错误:'N :: N(const N&)'是私有
t.cpp:26:错误:在此上下文中
这是一些真实代码的简化版本.
在实际代码中,我有一个包含std :: auto_ptr的类.这意味着采用const引用的复制构造函数无效(没有一些工作),我收到一个错误,表明复制构造函数因为它而不可用:
改变班级:
class N
{
public:
N(int) {}
private:
std::auto_ptr<int> data;
};
Run Code Online (Sandbox Code Playgroud)
那么错误是:
t.cpp:25:错误:没有用于调用'N :: N(N)'的匹配函数
dal*_*lle 15
来自http://gcc.gnu.org/gcc-3.4/changes.html
将类类型的rvalue绑定到引用时,必须可以访问该类的复制构造函数.例如,请考虑以下代码:
class A
{
public:
A();
private:
A(const A&); // private copy ctor
};
A makeA(void);
void foo(const A&);
void bar(void)
{
foo(A()); // error, copy ctor is not accessible
foo(makeA()); // error, copy ctor is not accessible
A a1;
foo(a1); // OK, a1 is a lvalue
}
Run Code Online (Sandbox Code Playgroud)
这可能是一见钟情,特别是因为大多数流行的编译器没有正确实现此规则(更多细节).
这将由Core Issue 391在C++ 1x中修复.
这里标准的适用部分是§8.5.3/ 5,它涵盖了引用的初始化和§3.10/ 6,它告诉了什么是rvalue和什么是左值(在C++中并不总是很明显).
在这种情况下,初始化表达式为:"N(1)",因此您使用功能表示法显式创建对象.根据3.10/6,该表达式是一个右值.
然后我们必须按顺序遍历8.5.3/5中的规则,并使用第一个适用的规则.第一种可能性是表达式表示左值,或者可以隐式转换为左值.你的表达式是一个rvalue,并且隐式转换为左值将需要一个返回引用的转换函数,在这种情况下似乎不存在,因此似乎不适用.
下一条规则说引用必须是const T(这里就是这种情况).在这种情况下,表达式是类类型的右值,并且与引用引用兼容(即引用是指同一个类,或类的基类).这意味着第151页底部的子弹(C++ 2003 PDF的179)似乎适用.在这种情况下,允许编译器将引用直接绑定到表示rvalue的对象,或者创建rvalue的临时副本,并绑定到该临时副本.
但是,无论哪种方式,标准明确要求:"无论副本是否实际完成,用于制作副本的构造函数都应该是可调用的."
因此,我认为 gcc提供错误信息是正确的,而其他人在技术上接受代码是错误的.我将您的代码简化为以下内容:
class N {
public:
N(int) {}
private:
N(N const&);
};
void plop(N const& data) { }
int main() {
plop(N(1));
}
Run Code Online (Sandbox Code Playgroud)
当使用"--A"(严格错误模式)调用时,Comeau会给出以下错误消息:
"plop.cpp", line 12: error: "N::N(const N &)", required for copy that was
eliminated, is inaccessible
plop(N(1));
^
Run Code Online (Sandbox Code Playgroud)
同样,当使用"/ Za"(其"ANSI符合"模式)调用时,VC++ 9给出:
plop.cpp
plop.cpp(12) : error C2248: 'N::N' : cannot access private member declared in class 'N'
plop.cpp(6) : see declaration of 'N::N'
plop.cpp(2) : see declaration of 'N'
while checking that elided copy-constructor 'N::N(const N &)' is callable
plop.cpp(6) : see declaration of 'N::N'
when converting from 'N' to 'const N &'
Run Code Online (Sandbox Code Playgroud)
我的猜测是大多数其他编译器大致相同.由于它们优化了对复制构造函数的调用,因此它们通常不需要它存在或可访问.当您要求他们尽可能准确地符合标准时,他们会给出错误消息,因为即使他们不使用它,它在技术上也是必需的.
| 归档时间: |
|
| 查看次数: |
3372 次 |
| 最近记录: |