代码之家  ›  专栏  ›  技术社区  ›  Fred Larson

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

  •  8
  • Fred Larson  · 技术社区  · 16 年前

    下面是一个说明问题的最低代码示例:

    #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,但没有得到诊断。为什么这里需要访问复制构造函数?除了使对象可复制(这不在我的控制范围内)或显式复制以传递(当复制实际对象的成本很高时),如何消除警告?

    4 回复  |  直到 11 年前
        1
  •  9
  •   Jerry Coffin    16 年前

    本标准§8.5.3/5中有相关规定。确定了三种基本情况。第一个涉及初始值设定项(在您的例子中为“3”),它要么是左值,要么是类类型。因为这两种情况都不是真的,所以第三种情况是:使用不具有类类型的rvalue初始化const引用。本案例包含在8.5.3/5中的最后一个项目符号中:

    否则,将使用非引用副本初始化规则(8.5),从初始值设定项表达式创建并初始化cv1 T1类型的临时副本。然后将引用绑定到临时对象。如果T1与T2相关,则cv1必须与cv2相同或大于cv2;否则,程序的格式就不正确。

    编辑:重读一遍,我认为IBM是对的。我之前考虑过复制临时文件的可能性,但这不是问题的根源。要使用§8.5中规定的非参考副本初始化创建临时副本,需要使用副本选择器。特别是,在这一点上,它相当于一个表达式,如:

    这基本上相当于:

    tx=T(a);

    而且

    T temp1(3);
    T temp2(temp1); // requires copy ctor
    show(temp2);    // show's reference parameter binds directly to temp2
    
        2
  •  3
  •   David Seiler    16 年前

    C++允许足够聪明的编译器避免复制临时对象,这是违反 仿佛 标准允许的规则。我不熟悉IBM的AIX C++编译器,但听起来好像是在思考 show(3)

    但是为什么呢 节目(3) 首先需要复印件吗?我不明白。运气好的话,利特一会儿就会来。

        3
  •  1
  •   Community Mohan Dere    5 年前

    我的直觉是杰瑞 answer 是正确的,但仍有一些问题。

    有趣的是,这一节的前一段涉及一个核心问题( 391 )。该问题与参数为同一类类型时有关。明确地:

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

    核心问题的变化 仅影响rvalue temporary具有相同类类型的位置。以前的措辞是:

    cv1 T1 引用是否与 cv2 T2, 参考文件的约束条件如下:

    [...]

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

    这最后一行就是我们要做的 show(Thing(3))

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

    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)
    }
    

    我不能在杰里对这个问题的解释中找到错误 foo (3) 然而,在这种情况下,由于不同编译器行为之间的差异,我确实有疑问。

        4
  •  0
  •   user200783    16 年前

    如果您尝试命名临时对象,会发生什么情况?

    Thing temp(3);
    show(temp);