为什么 IBM XL C/C 发出此警告?编译器?

发布于 2024-08-08 06:58:10 字数 1027 浏览 9 评论 0原文

下面是说明问题的最小代码示例:

#include <iostream>

class Thing
{
   // Non-copyable
   Thing(const Thing&);
   Thing& operator=(const Thing&);

   int n_;

public:
   Thing(int n) : n_(n) {}

   int getValue() const { return n_;}
};

void show(const Thing& t)
{
   std::cout << t.getValue() << std::endl;
}

int main()
{
   show(3);
}

这会产生相同的错误:

int main()
{
    show( Thing(3) );
}

AIX 下的 IBM XL C/C++ 8.0 编译器发出这些警告:

"testWarning.cpp", line 24.9: 1540-0306 (W) The "private" copy constructor "Thing(const Thing &)" cannot be accessed.
"testWarning.cpp", line 24.9: 1540-0308 (I) The semantics specify that a temporary object must be constructed.
"testWarning.cpp", line 24.9: 1540-0309 (I) The temporary is not constructed, but the copy constructor must be accessible.

我还尝试使用“-Wall”和“-pedantic”的 g++ 4.1.2,但没有得到任何诊断信息。为什么这里需要访问复制构造函数?除了使对象可复制(这超出了我的控制范围)或进行显式复制以传递(当现实生活中的对象复制成本很高时)之外,如何消除警告?

Here's a minimum code example that illustrates the problem:

#include <iostream>

class Thing
{
   // Non-copyable
   Thing(const Thing&);
   Thing& operator=(const Thing&);

   int n_;

public:
   Thing(int n) : n_(n) {}

   int getValue() const { return n_;}
};

void show(const Thing& t)
{
   std::cout << t.getValue() << std::endl;
}

int main()
{
   show(3);
}

This yields the same error:

int main()
{
    show( Thing(3) );
}

IBM XL C/C++ 8.0 compiler under AIX emits these warnings:

"testWarning.cpp", line 24.9: 1540-0306 (W) The "private" copy constructor "Thing(const Thing &)" cannot be accessed.
"testWarning.cpp", line 24.9: 1540-0308 (I) The semantics specify that a temporary object must be constructed.
"testWarning.cpp", line 24.9: 1540-0309 (I) The temporary is not constructed, but the copy constructor must be accessible.

I also tried g++ 4.1.2 with "-Wall" and "-pedantic" and got no diagnostic. Why is access to the copy constructor required here? How can I eliminate the warning, besides making the object copyable (which is outside my control) or making an explicit copy to pass (when the real-life object is expensive to copy)?

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

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

发布评论

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

评论(4

碍人泪离人颜 2024-08-15 06:58:10

相关规则位于标准的 §8.5.3/5 中。确定了三种基本情况。第一个涉及初始化程序(在您的情况下为“3”)是左值或具有类类型。由于这两种情况都不是真的,所以您遇到的是第三种情况:使用不具有类类型的右值初始化 const 引用。 8.5.3/5 中的最后一个项目符号涵盖了这种情况:

否则,将使用非引用复制初始化 (8.5) 的规则从初始化表达式创建并初始化类型为“cv1 T1”的临时变量。然后将该引用绑定到临时引用。如果 T1 与 T2 引用相关,则 cv1 的 cv 资格必须与 cv2 相同或更高;否则,该程序的格式不正确。

编辑:重读,我认为 IBM 说得对。我之前曾考虑过必须复制临时文件的可能性,但这不是问题的根源。要使用第 8.5 节中指定的非引用复制初始化来创建临时对象,需要复制构造函数。特别是,此时它相当于这样的表达式:

T x = a;

这基本上等价于:

T x = T(a);

即,需要创建一个临时对象,然后将该临时对象复制到正在初始化的对象(在本例中,该对象也是一个临时对象)。总结所需的过程,它大致相当于如下代码:

T temp1(3);
T temp2(temp1); // requires copy ctor
show(temp2);    // show's reference parameter binds directly to temp2

The rules for this are in §8.5.3/5 of the standard. There are three basic situations identified. The first involve the initializer ('3' in your case) being either an lvalue, or having class type. Since neither of those is true, what you have is the third case: initializing a const reference with an rvalue that does not have a class type. This case is covered by the final bullet in 8.5.3/5:

Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy initialization (8.5). The reference is then bound to the temporary. If T1 is reference-related to T2, cv1 must be the same cv-qualification as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed.

Edit: rereading, I think IBM has it right. I was previously thinking of the possibility of having to copy the temporary, but that's not the source of the problem. To create the temporary using non-reference copy initialization as specified in §8.5, it needs the copy ctor. In particular, at this point it's equivalent to an expression like:

T x = a;

This is basically equivalent to:

T x = T(a);

I.e. it's required to create a temporary, then copy the temporary to the object being initialized (which, in this case, is also a temporary). To summarize the required process, it's roughly equivalent to code like:

T temp1(3);
T temp2(temp1); // requires copy ctor
show(temp2);    // show's reference parameter binds directly to temp2
随波逐流 2024-08-15 06:58:10

C++ 允许足够智能的编译器避免复制临时对象,这是对标准允许的 as-if 规则的违反。我不熟悉 IBM 的 AIX C++ 编译器,但听起来它认为 show(3) 调用需要复制一个临时事物。在这种情况下,C++ 要求您有一个可访问的复制构造函数,即使您的编译器足够聪明,可以避免使用它。

但为什么 show(3) 首先需要副本呢?我无法弄清楚。运气好的话,litb 很快就会出现。

C++ permits sufficiently-smart compilers to avoid copying temporary objects, the one violation of the as-if rule allowed by the standard. I'm not familiar with IBM's AIX C++ compiler, but it sounds like it thinks the show(3) call requires a temporary Thing to be copied. In that case, C++ requires that you have an accessible copy constructor even though your compiler is smart enough to avoid using it.

But why does show(3) require a copy in the first place? That I can't figure out. With luck, litb will be along in a bit.

放血 2024-08-15 06:58:10

我的直觉是 Jerry 的答案是正确,但仍有一些问题。

有趣的是,有一个核心问题涵盖了该部分的前一段(391)。该问题与参数为同一类类型时有关。具体来说:

int main () {
  show ( Thing (3) );       // not allowed under current wording
                            // but allowed with Core Issue 391

  show ( 3 );               // Still illegal with 391
}

核心问题 391 中的更改仅影响右值临时具有相同类类型的情况。之前的措辞有:

如果初始化表达式是右值,T2 是类类型,并且 cv1 T1cv2 T2 引用兼容, 引用绑定如下:< /p>

[...]

无论复制是否实际完成,用于制作副本的构造函数都应该是可调用的。

根据当前标准,最后一行会使 show(Thing(3)) 非法。本节的拟议措辞是:

如果初始值设定项表达式是右值,T2 是类类型,并且“cv1 T1”与“cv2 T2”引用兼容,则引用将绑定到右值表示的对象(请参见 3.10 [basic.lval ]) 或该对象内的子对象。

此时,我认为 g++ 可能已按照 391 但更改意外地包含了复制初始化情况。然而,我测试的 g++ 版本并没有证明这一点:

class A{
public:
  A ();
  A (int);
private:
  A (A const &);
};

void foo (A const &);

void foo ()
{
  A a = 3 ;     // 3.2.3 (ERROR), 3.4.6(ERROR), 4.4.0(ERROR), Comeau(ERROR)
  
  foo ( 3 ) ;   // 3.2.3 (OK), 3.4.6(OK), 4.4.0(OK), Comeau(OK)
  foo ( A() );  // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
  foo ( A(3) ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
}

我无法在 Jerry 对 foo (3) 案例的解释中找到错误,但是,由于两者之间的差异,我确实有疑问。不同的编译器行为。

My gut feeling is that Jerry's answer is correct, but there are a few questions still.

What is interesting is that there is a core issue covering the previous paragraph of that section (391). That issue relates to when the argument is the same class type. Specifically:

int main () {
  show ( Thing (3) );       // not allowed under current wording
                            // but allowed with Core Issue 391

  show ( 3 );               // Still illegal with 391
}

The change in Core Issue 391 only affects where the rvalue temporary has the same class type. The previous wording had:

If the initializer expression is an rvalue, with T2 a class type, and cv1 T1 is reference-compatible with cv2 T2, the reference is bound as follows:

[...]

The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.

That last line is what would make show(Thing(3)) illegal as per the current standard. The proposed wording for this section is:

If the initializer expression is an rvalue, with T2 a class type, and "cv1 T1" is reference-compatible with "cv2 T2", the reference is bound to the object represented by the rvalue (see 3.10 [basic.lval]) or to a sub-object within that object.

At this point, I considered that g++ may have updated its behaviour as per 391 but that the change accidentally included the copy-initialization case. However, that is not demonstrated by the versions of g++ that I tested with:

class A{
public:
  A ();
  A (int);
private:
  A (A const &);
};

void foo (A const &);

void foo ()
{
  A a = 3 ;     // 3.2.3 (ERROR), 3.4.6(ERROR), 4.4.0(ERROR), Comeau(ERROR)
  
  foo ( 3 ) ;   // 3.2.3 (OK), 3.4.6(OK), 4.4.0(OK), Comeau(OK)
  foo ( A() );  // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
  foo ( A(3) ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
}

I cannot find fault in Jerry's interpretation for the foo (3) case, however, I do have doubts due to the discrepency between the different compiler behaviours.

云淡风轻 2024-08-15 06:58:10

如果您尝试命名临时事物会发生什么?

事物温度(3);
显示(临时);

What happens if you try naming the temporary Thing?

Thing temp(3);
show(temp);

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