Topic: Initialization subtleties and question about reasons


Author: Edward Diener <eldiener@tropicsoft.invalid>
Date: Wed, 2 Jun 2010 13:50:32 CST
Raw View
This is a little verbose but I felt I needed to enumerate the items in the
standard before asking my question(s).

In section 8,5 of the C++ Standard Initializers are discussed. In paragraph
11, first sentence, I read:

"The form of initialization (using parentheses or =) is generally
insignificant, but does matter when the
entity being initialized has a class type; see below."

Then in paragraph 12 the standard goes on to explain the terms
'copy-initialization' with its equivalent form and 'direct-initialization'
with its equivalent form. The paragraph reads:

"The initialization that occurs in argument passing, function return,
throwing an exception (15.1), handling
an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called
copy-initialization and is equivalent
to the form
T x = a;

The initialization that occurs in new expressions (5.3.4), static_cast
expressions (5.2.9), functional
notation type conversions (5.2.3), and base and member initializers (12.6.2=
)
is called direct-initialization
and is equivalent to the form
T x(a);"

In paragraph 14 item number 4 it then goes on to explain the difference
between direct-initialization and copy-initialization behavior when
initializing an object of class type with a source value. The text goes:

"=97 If the initialization is direct-initialization, or if it is
copy-initialization where the cv-unqualified version
of the source type is the same class as, or a derived class of, the class o=
f
the destination, constructors
are considered. The applicable constructors are enumerated (13.3.1.3), and
the best one is
chosen through overload resolution (13.3). The constructor so selected is
called to initialize the
object, with the initializer expression(s) as its argument(s). If no
constructor applies, or the overload
resolution is ambiguous, the initialization is ill-formed.

=97 Otherwise (i.e., for the remaining copy-initialization cases),
user-defined conversion sequences that
can convert from the source type to the destination type or (when a
conversion function is used) to a
derived class thereof are enumerated as described in 13.3.1.4, and the best
one is chosen through
overload resolution (13.3). If the conversion cannot be done or is
ambiguous, the initialization is
ill-formed. The function selected is called with the initializer expression
as its argument; if the function
is a constructor, the call initializes a temporary of the destination type.
The result of the call
(which is the temporary for the constructor case) is then used to
direct-initialize, according to the
rules above, the object that is the destination of the copy-initialization.
In certain cases, an implementation
is permitted to eliminate the copying inherent in this direct-initializatio=
n
by constructing
the intermediate result directly into the object being initialized; see
12.2, 12.8."

Now finally let's consider the initialization of global/static class object=
s
as opposed to class objects that are non-static members of another class.
Given a class:

class X
{
public:
explicit X(int y)
{
// any code
}
};

class Y
{
public:
X x;
Y();
};

when initializing the value X x in Y's constructor I can write:

Y::Y() : x(0)
{
}

But if I try to initial a global object of type X in the same way, using
direct initialization syntax, the compiler rejects it:

X x2(0);

So I am forced to initialize my global x2 value using the
copy-initialization syntax of:

X x2 = 0;

and now the subtle difference mentioned in section 8.5 paragraph 11, and
explained more fully in the subsequent citations above, kicks in.
The compiler tells me I have an error because I am no longer initializing m=
y
x2 value using the direct-initialization constructor but I am instead using
the copy-initializer and there is no conversion between my '0' value, an
int, and my class X because my constructor is
'explicit'. To succeed when intializing my global object I must write:

X x2 = X(0);

This appears to be a really unwanted anomaly of the language. On the one
hand, initializating the non-static member uses what appears to me to be th=
e
absolutely normal initialization of calling the constructor of X and passin=
g
an 'int' to it. But my efforts to initialize the global object must use the
= initialization syntax, therefore triggering copy-initialization and
therefore forcing the second syntax above because of the explicit
constructor.

Why was C++ designed this way ? At the very least, given the subtle
difference between the '=' and '(...)' initialization syntaxes, why was o=
ne
not allowed to use the latter, as well as the former, when initializing
global/static objects ? Clearly I should be able to create the global objec=
t
by directly invoking its constructor when I create it whether my constructo=
r
is 'explicit' or not. But as I have shown I can not do that. To me this
indicates something wrong in the design of C++ when it comes to
initialization, as I hope I have shown here.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Paul Bibbings <paul.bibbings@gmail.com>
Date: Thu, 3 Jun 2010 14:53:52 CST
Raw View
Edward Diener <eldiener@tropicsoft.invalid> writes:
<snip />

> Now finally let's consider the initialization of global/static class
> objects as opposed to class objects that are non-static members of
> another class.
> Given a class:
>
> class X
> {
> public:
> explicit X(int y)
> {
> // any code
> }
> };
>
> class Y
> {
> public:
> X x;
> Y();
> };
>
> when initializing the value X x in Y's constructor I can write:
>
> Y::Y() : x(0)
> {
> }
>
> But if I try to initial a global object of type X in the same way, using
> direct initialization syntax, the compiler rejects it:
>
> X x2(0);

It may be that I have misunderstood what you intend by "initial[ize] a
global object of type X in the same way, using direct initialization
syntax."  However, assuming the following to be a correct
interpretation, I am unable to reproduce the "compiler rejection" you
have identified here.  Nor would I expect to.

  10:05:54 Paul Bibbings@JIJOU
  /cygdrive/d/CPPProjects/CSCPP $cat init_subtleties.cpp

  class X {
  public:
     explicit X(int y) { }
  };

  class Y
  {
  public:
     X x;
     Y();
  };

  Y::Y()
     : x(0)  // mem-initializer, direct initialization
  { }

  X x2(0);   // global, direct initialization


  10:06:00 Paul Bibbings@JIJOU
  /cygdrive/d/CPPProjects/CSCPP $i686-pc-cygwin-gcc-4.4.3 -ansi
     -pedantic -c init_subtleties.cpp

  10:06:28 Paul Bibbings@JIJOU
  /cygdrive/d/CPPProjects/CSCPP $

I get the same results with VC++ 2008 and Comeau.

<snip />

Regards

Paul Bibbings

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Yechezkel Mett <ymett.on.usenet@gmail.com>
Date: Thu, 3 Jun 2010 14:54:55 CST
Raw View
On Jun 2, 10:50 pm, Edward Diener <eldie...@tropicsoft.invalid> wrote:
>
> class X
> {
> public:
> explicit X(int y)
> {
> // any code
>
> }
> };
>
...
> But if I try to initial a global object of type X in the same way, using
> direct initialization syntax, the compiler rejects it:
>
> X x2(0);
>

No it doesn't. Maybe the rejected code was something else?

Yechezkel Mett


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Thu, 3 Jun 2010 14:54:55 CST
Raw View
On 2 Jun., 21:50, Edward Diener <eldie...@tropicsoft.invalid> wrote:
> This is a little verbose but I felt I needed to enumerate the items in the
> standard before asking my question(s).
>
> In section 8,5 of the C++ Standard Initializers are discussed. In paragraph
> 11, first sentence, I read:

[lots of quoted wording omitted]

> Now finally let's consider the initialization of global/static class
> objects as opposed to class objects that are non-static members
> of another class.
> Given a class:
>
> class X
> {
> public:
> explicit X(int y)
> {
> // any code
> }
> };

OK, this is a class with an explicit c'tor.

> But if I try to initial a global object of type X in the same way, using
> direct initialization syntax, the compiler rejects it:
>
> X x2(0);

I don't understand why this initialization should be ill-formed. Your
quoted wording falls into ISO/IEC 14882:2003(E), 8.5/14 b. 4
("If the destination type is a (possibly cv-qualified) class type"),
sb. 2 ("If the initialization is direct-initialization") and this is
clearly
direct initialization and should select the explicit c'tor X(int).
Which compiler rejects this?

> So I am forced to initialize my global x2 value using the
> copy-initialization syntax of:
>
> X x2 = 0;
>
> and now the subtle difference mentioned in section 8.5 paragraph 11, and
> explained more fully in the subsequent citations above, kicks in.
> The compiler tells me I have an error because I am no longer initializing m=
> y
> x2 value using the direct-initialization constructor but I am instead using
> the copy-initializer and there is no conversion between my '0' value, an
> int, and my class X because my constructor is
> 'explicit'.

IMO this is the expected behavior for this initializer.

> To succeed when intializing my global object I must write:
>
> X x2 = X(0);
>
> This appears to be a really unwanted anomaly of the language. On the one
> hand, initializating the non-static member uses what appears to me to be th=
> e
> absolutely normal initialization of calling the constructor of X and passin=
> g
> an 'int' to it. But my efforts to initialize the global object must use the
> = initialization syntax, therefore triggering copy-initialization and
> therefore forcing the second syntax above because of the explicit
> constructor.

Why should you trigger copy-initialization? You want and need the
direct-initialization.

> Why was C++ designed this way ? At the very least, given the subtle
> difference between the '=' and '(...)' initialization syntaxes, why was
> one not allowed to use the latter, as well as the former, when initializing
> global/static objects ?

Here must be some misunderstanding, direct-initialization should
be the right thing here.

HTH & Greetings from Bremen,

Daniel Kr   gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Edward Diener <eldiener@tropicsoft.invalid>
Date: Fri, 4 Jun 2010 11:52:14 CST
Raw View
On 6/3/2010 4:54 PM, Daniel Kr=FCgler wrote:

> On 2 Jun., 21:50, Edward Diener<eldie...@tropicsoft.invalid>  wrote:
>
>> This is a little verbose but I felt I needed to enumerate the items in t=
he
>> standard before asking my question(s).
>>
>> In section 8,5 of the C++ Standard Initializers are discussed. In
>> paragraph
>> 11, first sentence, I read:
>>
>
> [lots of quoted wording omitted]
>
> Now finally let's consider the initialization of global/static class
>> objects as opposed to class objects that are non-static members
>> of another class.
>> Given a class:
>>
>> class X
>> {
>> public:
>> explicit X(int y)
>> {
>> // any code
>> }
>> };
>>
>
> OK, this is a class with an explicit c'tor.
>
> But if I try to initial a global object of type X in the same way, using
>> direct initialization syntax, the compiler rejects it:
>>
>> X x2(0);
>>
>
> I don't understand why this initialization should be ill-formed. Your
> quoted wording falls into ISO/IEC 14882:2003(E), 8.5/14 b. 4
> ("If the destination type is a (possibly cv-qualified) class type"),
> sb. 2 ("If the initialization is direct-initialization") and this is
> clearly
> direct initialization and should select the explicit c'tor X(int).
> Which compiler rejects this?
>
> So I am forced to initialize my global x2 value using the
>> copy-initialization syntax of:
>>
>> X x2 = 0;
>>
>> and now the subtle difference mentioned in section 8.5 paragraph 11, and
>> explained more fully in the subsequent citations above, kicks in.
>> The compiler tells me I have an error because I am no longer initializin=
g
>> m=
>> y
>> x2 value using the direct-initialization constructor but I am instead
>> using
>> the copy-initializer and there is no conversion between my '0' value, an
>> int, and my class X because my constructor is
>> 'explicit'.
>>
>
> IMO this is the expected behavior for this initializer.
>
> To succeed when intializing my global object I must write:
>>
>> X x2 = X(0);
>>
>> This appears to be a really unwanted anomaly of the language. On the one
>> hand, initializating the non-static member uses what appears to me to be
>> th=
>> e
>> absolutely normal initialization of calling the constructor of X and
>> passin=
>> g
>> an 'int' to it. But my efforts to initialize the global object must use
>> the
>> = initialization syntax, therefore triggering copy-initialization and
>> therefore forcing the second syntax above because of the explicit
>> constructor.
>>
>
> Why should you trigger copy-initialization? You want and need the
> direct-initialization.
>
> Why was C++ designed this way ? At the very least, given the subtle
>> difference between the '=' and '(...)' initialization syntaxes, why wa=
s
>> one not allowed to use the latter, as well as the former, when
>> initializing
>> global/static objects ?
>>
>
> Here must be some misunderstanding, direct-initialization should
> be the right thing here.
>

My apologies to all and for the noise. I had run into what I thought was a
rejection of direct initialization syntax for global/static variables in
VC++ 9 and had thought it meant that C++ itself rejected such syntax. But I
can no longer produce the exact situation which occurred.

Thanks for everyone's intelligent answers pointing out my mistake. I had
been so used to using the '=' initialization syntax exclusively for
global/static variables that I had not realized that the '(...)' was also
valid in this case, and in some situation when I had tried to use the
'(...)' syntax it had failed. But as I said I can no longer produce it and
so must assume it was my own error in some way.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]