为什么在这段代码中使用复制因子?

发布于 2024-07-22 08:36:42 字数 1072 浏览 3 评论 0原文

class A
{
 public:
  A(const int n_);
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ cout << "A::operator=(const A&)" << endl; }

int foo(const A& a_)
{ return 20; }

int main()
{
  A a(foo(A(10)));    // This is line 38
  return 0;
}

执行这段代码给出o/p:

A::A(int),n_=10
A::A(int),n_=20

显然复制构造函数从未被调用。

class A
{
 public:
  A(const int n_);
  A& operator=(const A& that_);
 private:
  A(const A& that_);
};

但是,如果我们将其设为私有,则会出现以下编译错误:

Test.cpp:在函数“int main()”中:
Test.cpp:21: 错误:'A::A(const A&)' 是私有的
Test.cpp:38:错误:在此上下文中

为什么编译器在实际不使用复制构造函数时会抱怨?
我使用的是 gcc 版本 4.1.2 20070925 (Red Hat 4.1.2-33)

class A
{
 public:
  A(const int n_);
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ cout << "A::operator=(const A&)" << endl; }

int foo(const A& a_)
{ return 20; }

int main()
{
  A a(foo(A(10)));    // This is line 38
  return 0;
}

Executing this code gives o/p:

A::A(int), n_=10
A::A(int), n_=20

Apparently the copy constructor is never called.

class A
{
 public:
  A(const int n_);
  A& operator=(const A& that_);
 private:
  A(const A& that_);
};

However, if we make it private, this compile error occurs:

Test.cpp: In function ‘int main()’:
Test.cpp:21: error: ‘A::A(const A&)’ is private
Test.cpp:38: error: within this context

Why does the compiler complain when it doesn't actually use the copy constructor?
I am using gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

对你再特殊 2024-07-29 08:36:43

不使用复制构造函数,但为了编译代码,复制构造函数需要可访问。

编辑:Comeau C++ 编译器报告以下内容:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 38: error: "A::A(const A &)" (declared at line 17), required
          for copy that was eliminated, is inaccessible
    A a(foo(A(10)));    // This is line 38
            ^

1 error detected in the compilation of "ComeauTest.c".

请注意,如果启用了 C++0x 扩展,则它可以在 Comeau C++ 编译器中正常编译。

The copy-constructor isn't used, but in order for the code to compile the copy-constructor need to be accessible.

EDIT: Comeau C++ compiler reports the following:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 38: error: "A::A(const A &)" (declared at line 17), required
          for copy that was eliminated, is inaccessible
    A a(foo(A(10)));    // This is line 38
            ^

1 error detected in the compilation of "ComeauTest.c".

Note that if C++0x extensions are enabled, it compiles fine in Comeau C++ compiler.

笛声青案梦长安 2024-07-29 08:36:43

一般来说,您不应该担心复制构造函数是否以及何时被调用。 C++ 标准对于何时删除或添加对复制构造函数的调用相当宽松。 如果您的类在逻辑上需要它,则提供它(并且不要忘记析构函数和赋值运算符)是明智的规则。

In general, you shouldn't get to worried about if and when the copy constructor gets called. The C++ Standard is pretty relaxed about when calls to the copy constructor will be removed, or for that matter added. If your class logically needs it, provide it (and don't forget the destructor and assignment operator) is the sensible rule.

囍孤女 2024-07-29 08:36:43

调用时:

foo( A(10) );

在调用的生命周期内创建临时对象。 正在使用复制构造函数来填充数据。 执行调用后,临时对象将被删除。

调用时:

{ 
  A original(10);
  foo( original ); 
}

退出块后原始数据被丢弃。 它可以安全地用作参数。

为了获得最佳速度,请使用编译器在优化期间将丢弃的临时变量通过引用传递对象。

When calling:

foo( A(10) );

a temporary object is being created during the lifetime of the call. A copy constructor is being being used to populate the data. The temporary object is removed after execution of the call.

When calling:

{ 
  A original(10);
  foo( original ); 
}

The original is being discarded after exiting the block. It can safely be used as a parameter.

For optimal speed, pass the object by reference, using a temporary variable that will be discarded by the compiler during its optimization.

淡淡の花香 2024-07-29 08:36:42

核心缺陷 391 解释了该问题。

基本上,当前的 C++ 标准要求在将类类型的临时值传递给 const 引用时提供可用的复制构造函数。

此要求将在 C++0x 中删除。

需要复制构造函数背后的逻辑来自这种情况:

C f();
const C& r = f(); // a copy is generated for r to refer to

Core defect 391 explains the issue.

Basically, the current C++ standard requires a copy constructor to be available when passing a temporary of class type to a const reference.

This requirement will be removed in C++0x.

The logic behind requiring a copy constructor comes from this case:

C f();
const C& r = f(); // a copy is generated for r to refer to
一影成城 2024-07-29 08:36:42

2003 年标准第 §12.2/1 条规定:

即使创建
避免临时对象(12.8),
所有语义限制必须是
如同临时物品一样受到尊重
被创建。 [示例:即使
复制构造函数没有被调用,全部
语义限制,例如
可访问性(第 11 条),应
使满意。 ]

周围还有类似的例子。 据我所知,编译器可以自由地生成临时文件或优化它们。

The 2003 standard, in §12.2/1, states:

Even when the creation of the
temporary object is avoided (12.8),
all the semantic restrictions must be
respected as if the temporary object
was created. [Example: even if the
copy constructor is not called, all
the semantic restrictions, such as
accessibility (clause 11), shall be
satisfied. ]

There are similar examples around. From what I gather, the compiler is free to generate temporaries or optimize them away.

Smile简单爱 2024-07-29 08:36:42

据我所知,您没有在任何地方使用复制构造函数。 在语句 foo(A(10)) 中,您创建了 A 类的临时对象,并将其作为常量引用传递给 foo。 foo 返回一个整数,用于构造对象a。 因此,我不知道复制构造函数在哪里参与其中,也不知道 NRVO 是如何出现的。 另外,我通过将复制构造函数设置为私有来编译以下代码,并且它在 VS2008 中编译良好。

using namespace std;

class A
{
 public:
  A(const int n_);
 private:
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ 
    cout << "A::operator=(const A&)" << endl; 
    return *this;
}

int foo(const A& a_)
{ return 20; }


int main(int argc,char *argv[])
{
   A a(foo(A(10)));    // This is line 38
  return 0;

}   

As far I see you are not using the copy constructor anywhere. In the statement foo(A(10)) you are creating a temporary object of class A and passing it as a const-reference to foo. The foo returns an integer which is used in the construction of object a. Hence I don't see where the copy constructor is getting involved here and how NRVO comes into picture. Also, I compiled the following code by making the copy constructor private and it compiled fine in VS2008.

using namespace std;

class A
{
 public:
  A(const int n_);
 private:
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ 
    cout << "A::operator=(const A&)" << endl; 
    return *this;
}

int foo(const A& a_)
{ return 20; }


int main(int argc,char *argv[])
{
   A a(foo(A(10)));    // This is line 38
  return 0;

}   
·深蓝 2024-07-29 08:36:42

另一句话:编译器在使用临时变量时会做不同的事情。 所以这不是关于复制构造函数,而是关于中间临时变量。

A original(10);
foo( original ); // does compile
foo( A(10) ); // doesn't compile - needs a copy constructor

Just another remark: the compiler does a different thing when working with a temporary. So it's not about the copy constructor, it's about the intermediate temporary.

A original(10);
foo( original ); // does compile
foo( A(10) ); // doesn't compile - needs a copy constructor
少女的英雄梦 2024-07-29 08:36:42

在表达式中:

A a(foo(A(10)));

子表达式 A(10) 的结果是 A 类型的右值。 (5.2.3 [expr.type.conv])

当从右值初始化常量引用时,编译器可以从右值创建一个临时变量并将其绑定到引用。 即使选择不这样做,复制构造函数也必须是可访问的。 (8.5.3 [decl.init.ref])如果从强制直接绑定的引用兼容左值初始化引用,则情况不会如此。

由于 foo 通过引用而不是值获取其参数,因此参数初始化本身不需要强制复制。

foo 返回一个 int,因此这里没有 A 的副本。

a 是直接从 foo 返回的 int 初始化的,因此这里没有 A 的副本。

In the expression:

A a(foo(A(10)));

The result of the sub-expression A(10) is an rvalue of type A. (5.2.3 [expr.type.conv])

When initializing a const reference from an rvalue the compiler may create a temporary from the rvalue and bind that to the reference. Even if it chooses not to, the copy constructor must be accessible. (8.5.3 [decl.init.ref]) This would not be the case if there reference were being initialized from a reference-compatible lvalue where direct binding is mandated.

As foo takes its parameter by reference and not value, there is no copy mandated for the argument initialization itself.

foo returns an int, so there is no copy of an A here.

a is direct initialized from the int returned by foo, so there is no copy of A here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文