Why is this a warning from the IBM XL C / C ++ compiler?

Here is an example of minimal code 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 gives the same error:

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

The IBM XL C / C ++ 8.0 compiler on AIX displays the following 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 did not get any diagnostics. Why is access to the copy constructor needed here? How can I eliminate this warning, in addition to copying an object (which is beyond my control) or making an explicit copy for transmission (when a real object is expensive to copy)?

+8
c ++ compiler-warnings aix ibm
Oct 23 '09 at 20:15
source share
4 answers

The rules for this are given in clause 8.5.3 / 5 of the standard. Three main situations stand out. The first includes an initializer ('3' in your case), either an lvalue or a class type. Since none of them is true, you have a 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, the temporary type “cv1 T1” is created and initialized from the initializer expression using the rules for initialization without reference (8.5). The link is then linked to a temporary one. If T1 is associated with a link T2, cv1 must be the same cv qualification as or a higher cv qualification than cv2; otherwise the program is poorly formed.

Edit: re-read, I think IBM is doing fine. I used to think about being able to copy temporary, but not as a source of the problem. To create a temporary initialization without a reference, as described in section 8.5, she needs a copy of ctor. In particular, at this moment this is equivalent to an expression of the form:

T x = a;

This is basically equivalent to:

T x = T (a);

those. it must create a temporary one and then copy the temporary object initialized (which in this case is also temporary). To summarize the required process, it is roughly equivalent to code like:

 T temp1(3); T temp2(temp1); // requires copy ctor show(temp2); // show reference parameter binds directly to temp2 
+9
Oct 23 '09 at 20:50
source share

C ++ allows smart compilers to avoid copying temporary objects, one violation of the as-if rule allowed by the standard. I am not familiar with the IBM AIX C ++ compiler, but it seems that calling show(3) requires a temporary copy of Thing. In this case, C ++ requires that you have an available copy constructor, even if your compiler is smart enough to avoid using it.

But why does show(3) require a copy in the first place? That I cannot understand. With luck, litb will be a bit.

+3
Oct 23 '09 at 20:26
source share

I feel like Jerry has the correct answer , but there are a few more questions.

Interestingly, there is a major problem covering the previous paragraph of this section ( 391 ). This problem refers to when the argument is the same type of class. In particular:

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

Changing Core Issue 391 only affects where the temporary rvalue is of the same class type. In the previous edition were:

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

[...]

The constructor that will be used to create the copy must be called regardless of whether the copy is actually executed.

This last line is what would make show(Thing(3)) illegal according to the current standard. Suggested wording for this section:

If the initializer expression is an rvalue, and T2 is a class type, and "cv1 T1" refers to "cv2 T2", the link is attached to the object represented by the rvalue value (see 3.10 [basic.lval]) or to a sub-object inside this object.

At this point, I thought that g ++ could update its behavior to 391 , but this change accidentally included copy-case initialization. However, this is not confirmed by the g ++ versions 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 a mistake in Jerry's interpretation for the case of foo (3) , however, I have doubts due to the discrepancy between the different compiler behaviors.

+1
Oct 26 '09 at 13:15
source share

What happens if you try to name a temporary thing?

Thing temp(3);
show(temp);

0
Oct 23 '09 at 20:41
source share