Convert conditional statement in VS 2012

I am currently converting a rather large project from VS 2008 to 2012, and I had a problem with changing the way the conditional operator type is converted.

To begin with, I agree that the semantics of a conditional statement are somewhat complex and understand what the code does initially. This is probably not true, but I'm really confused about what is happening now in VS 2012, and I was wondering if someone could explain exactly why he is doing what he is doing.

class DummyString { wchar_t wchBuf[32]; public: DummyString() { *wchBuf = 0; } DummyString(int) { *wchBuf = 0; } DummyString(const DummyString& ds) { *wchBuf = 0; } operator const wchar_t*() const { return wchBuf; } }; int _tmain(int argc, _TCHAR* argv[]) { DummyString ds; // note: the argc test is simply to stop the conditional operator // being optimised away const wchar_t* pPtr = (argc == 100) ? 0 : ds; assert(pPtr == static_cast<const wchar_t*>(ds)); return 0; } 

In VS 2008, the conditional operator above will cause the operator const wchar_t*() method to be called on ds and the statement will fail. That is, it will implicitly discard ds in const wchar_t* .

In VS 2012, a conditional statement leads to the following behavior:

  • Temporary DummyString is created using the copy constructor
  • At the same time, const wchar_t* is executed on <temporary copying>

This leads to the fact that pPtr remains to point to the destroyed object, and the statement, of course, works.

Now, if I DummyString(int) constructor from the class, the code will not compile in VS2012 (without converting from "DummyString" to "int"), so it is clear that 0 in the conditional expression causes the expression to evaluate to int, not a pointer.

But in this case, why isn't the DummyString(int) constructor DummyString(int) to convert 0 to DummyString ? And why does the compiler create a copy of ds and then discard it on wchar_t * when it can just as easily throw on the original object?

I would like to be enlightened! :)

+8
c ++ c ++ 11 visual-c ++ visual-studio-2012
source share
2 answers

Paragraph 5.16 / 3 of the C ++ 11 standard indicates that:

[...] if the second and third operands are of different types and have a (possibly cv-qualified) type class, or if both are values ​​of the same value category of the same type, except for cv-qualification, an attempt is made convert each of these operands to the type of the other . [...]

So what:

[...] If both can be converted, or you can convert, but the conversion is ambiguous, the program is poorly formed. If neither can be converted, the operands remain unchanged, and further verification is performed as described below. If one conversion is possible, this conversion is applied to the selected operand and the converted operand is used instead of the original operand for the rest of this section.

In this case, only conversion from int to DummyString , since in the other direction a const wchar_t* , as far as we can go, there is no standard implicit conversion from const wchar_t* to int .

This is why the compiler complains if you remove the conversion constructor that accepts int : if this constructor did not exist, according to the paragraph above, the program would be poorly formed (the conversion would not be in any direction).

Therefore, the second operand (first choice) is considered DummyString(0) .

However, the fact that the second operand can be converted to a DummyString does not mean that the second operand will be evaluated at all. It depends on the condition, and the condition evaluates to false (unless you pass 100 arguments to the command line), which explains why you don't see the call to this constructor. In paragraph 5.16 / 1:

Group conditional expressions from right to left. The first expression is contextually converted to bool (section 4). It is evaluated and, if true, the result of the conditional expression is the value of the second expression, otherwise the third expression. Only one of the second and third expressions is evaluated. [...]

But why does your statement fail?

And why does the compiler create a copy of ds and then discard it on wchar_t* when it can just as easily throw on the original object?

Well, this is because of clauses 5.16 / 4-5:

If the second and third operands are glvalues ​​of the same category of values ​​and are of the same type, [...]

Otherwise, the result will be prvalue . If the second and third operands do not have the same type and have a (possibly cv-qualified) class type, overload resolution is used to determine conversions (if any) applied to operands (13.3.1.2, 13.6).

0 not a glvalue value, so the result of the conditional will be prvalue. This means evaluating the conditional operator under false will create a temporary one from ds , which is the behavior you observe.

This is stated in paragraph 5.16 / 6, which states:

The standard values ​​of the Lvalue-to-rvalue conversion (4.1), the array-to-pointer conversion (4.2), and the standard conversion of the to-pointer function (4.3) on the second and third operands are performed. After these transformations, one of the following actions will be performed:

- The second and third operands are of the same type; result of this type. If the operands are of class type, the result is a temporary prvalue value for the result type, which is initialized with a copy from the second operand or third operand , depending on the value of the first operand. [...]

The condition `` the second and third operands are of the same type '', because now the operands are considered after the conversion described in 5.16 / 3 (see the beginning of this answer).

To fix your problem, you can perform an explicit conversion on the second argument:

 const wchar_t* pPtr = (argc == 100) ? 0 : static_cast<const wchar_t*>(ds); 

Since a standard conversion from 0 to a pointer type exists and leads to a null pointer - see paragraph 4.10 / 1.

+13
source share

If you want, you can avoid calling the copy constructor by specifying this:

 const wchar_t* pPtr = (argc == 100) ? 0 : (pPtr = ds); 
0
source share

All Articles