Topic: It still is weird, but I understand it now :)
Author: Biju Thomas <b_thomas@ibm.net>
Date: 1999/11/09 Raw View
"J.Barfurth" wrote:
>
> > > > Type var = Type(istream_iterator<Type>(is),
> > > > istream_iterator<Type>());
> > > >
> > > This is correct. It is likely to be rather inefficient.
>
> > No, it is not inefficient.
> I agree that it is not _likely_ to be inefficient.
>
[...]
> The compiler may elide copying those temporaries though (see 12.8/15 - iirc
> there is wording to that effect in the the section about initialization as
> well).
>
[...]
> Only if overload resolution selects a copy constructor or if the compiler
> can determine that the constructor which would be invoked has no side
> effects this may be optimized to avoid the temporary.
Okay, I agree with everything that you wrote in this post except this
last sentence -- the standard allows compilers to omit copy constructors
in cases such as the above one even if the copy constructor has
side-effects. (Based on 12.8/15).
(Thanks to John Potter also for his reply.)
--
Biju Thomas
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Biju Thomas <b_thomas@ibm.net>
Date: 1999/11/08 Raw View
Dietmar Kuehl wrote:
>=20
> In article <7vbu9a$gfr$1@nnrp1.deja.com>,
> Jeet Sukumaran <jeet_sukumaran@my-deja.com> wrote:
>=20
> > As Bill indicated,
> >
> > Type var =3D Type(istream_iterator<Type>(is),
> > istream_iterator<Type>());
> >
> > would work, but it looks to me inefficient (is it?), since it creates
> > two variables, initializes the anonymous one, then assigns it to the
> > named one (right?)
>=20
> This is correct. It is likely to be rather inefficient.
>=20
No, it is not inefficient. According to the standard (8.5/14), copy
initialization of the above category is equivalent to direct
initialization. There is no temporary variable or copy constructor
involved -- the object is constructed right into the variable 'var'.
Here is the relevant part from the standard:
<quote>
If the initialization is direct=ADinitialization, or if it is
copy=ADinitialization where the cv=ADunqualified version of the source ty=
pe
is the same class as, or a derived class of, the class of 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). [...]
</quote>
--=20
Biju Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "J.Barfurth" <techview@bfk-net.de>
Date: 1999/11/08 Raw View
Biju Thomas <b_thomas@ibm.net> schrieb in im Newsbeitrag:
38262FAC.97F8AFC@ibm.net...
> Dietmar Kuehl wrote:
>
> > In article <7vbu9a$gfr$1@nnrp1.deja.com>,
> > Jeet Sukumaran <jeet_sukumaran@my-deja.com> wrote:
> > > Type var =3D Type(istream_iterator<Type>(is),
> > > istream_iterator<Type>());
> > >
> > This is correct. It is likely to be rather inefficient.
> No, it is not inefficient. According to the standard (8.5/14), copy
> initialization of the above category is equivalent to direct
> initialization. There is no temporary variable or copy constructor
> involved -- the object is constructed right into the variable 'var'.
I agree that it is not _likely_ to be inefficient. The object needn't be
constructed right into 'var'. The straightforward translation of the abov=
e
would produce the same code as:
istream_iterator<Type> ii_begin(is); // temporary constructed
istream_iterator<Type> ii_end; // temporary constructed
Type tmp(ii_begin,ii_end); // temporary constructed
Type var(tmp);
// temporaries (tmp,ii_end,ii_begin) destructed here
The compiler may elide copying those temporaries though (see 12.8/15 - ii=
rc
there is wording to that effect in the the section about initialization a=
s
well).
> Here is the relevant part from the standard:
> <quote>
> If the initialization is direct=ADinitialization, or if it is
> copy=ADinitialization where the cv=ADunqualified version of the source =
type
> is the same class as, or a derived class of, the class of 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). [...=
]
> </quote>
But in the case of 'copy initialization where...' the 'applicable
constructors' will usually(*) be the copy constructor(s) of Type. [(*) Se=
e
auto_ptr copying for an example of how other constructors may enter the
scene].
The initializer expression, which would have to be evaluated to provide t=
he
arguments for the constructor selected is:
'Type(istream_iterator<Type>(is),istream_iterator<Type>())'.
It constructs a temporary 'Type' object, which is then passed to the
selected constructor as an argument.
Only if overload resolution selects a copy constructor or if the compiler
can determine that the constructor which would be invoked has no side
effects this may be optimized to avoid the temporary.
-- J=F6rg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/11/08 Raw View
On 08 Nov 99 04:03:51 GMT, Biju Thomas <b_thomas@ibm.net> wrote:
: Dietmar Kuehl wrote:
: >=20
: > In article <7vbu9a$gfr$1@nnrp1.deja.com>,
: > Jeet Sukumaran <jeet_sukumaran@my-deja.com> wrote:
: >=20
: > > As Bill indicated,
: > >
: > > Type var =3D Type(istream_iterator<Type>(is),
: > > istream_iterator<Type>());
: > >
: > > would work, but it looks to me inefficient (is it?), since it creates
: > > two variables, initializes the anonymous one, then assigns it to the
: > > named one (right?)
: >=20
: > This is correct. It is likely to be rather inefficient.
: >=20
:
: No, it is not inefficient. According to the standard (8.5/14), copy
: initialization of the above category is equivalent to direct
: initialization. There is no temporary variable or copy constructor
: involved -- the object is constructed right into the variable 'var'.
Check that again. It talks about both direct initialization and one
case of copy initialization.
int i1(5); // direct initialization using the copy ctor.
int i2 = i1; // copy initialization via direct initialization using
// the copy ctor.
int i3 = int(2.5); // int i3(int(2.5)); uses copy ctor but may (
// not must) be optimized out.
class C {
public :
C (int i) : v(i) { }
private :
int v;
C (C const&);
};
C c1(5); // direct initialization
C c2 = 5; // copy initialization, not same type, invalid
C c3 = C(5); // direct initialization using copy ctor. Still invalid.
John
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Dietmar Kuehl <dietmar.kuehl@claas-solutions.de>
Date: 1999/11/03 Raw View
Hi,
In article <7vbu9a$gfr$1@nnrp1.deja.com>,
Jeet Sukumaran <jeet_sukumaran@my-deja.com> wrote:
> Just when you think you that you understand at least certain aspects
> of the language!
Actually, the exact example you have given (well, instead of using 'in'
the standard stream 'cin' was used) was shown to a whole bunch of
members of C++ standardization committee at the meeting in April 1997
(that is the Sophia Antipolis meeting). With one exception all of those
who looked at this declaration explained that it is a definition of a
'vector<int>'. The only person who did not consider it a definition
already knew that it is not a definition and took quite a while before
he could explain what it really is.
> I am still trying to figure out why the compiler is
> not confused by the second argument, and, for that matter, the logic
> behind the whole thing. Has it got to do with operator precedence?
It has nothing to do with operator precedence at all. The logic is quite
simple: If 'X' is a type 'X()' might either declare a function returning
an object of type 'X' or invoke the default constructor of 'X'. Which of
those depends on the context: In expressions, 'X()' is clearly the call
of the default constructor, in declarations 'X()' is the declaration
unless it is preceeded by a '=' in which case it defines a default
argument.
Analogously, 'X(in)' can either be a declaration of an object called
'in' or the call of an constructor where 'in' is the constructor
argument. The tricky thing are the parenthesis around 'in': These are
allowed but actually not needed in this case.
Now, fitting it all together, it turns out that
std::vector<int> buf(std::istream_iterator<int>(in),
std::istream_iterator<int>());
can be parsed both as a declaration of a function or a defintion of an
object. The standard specifies that this ambiguity is resolved in favor
of the declaration.
> As Bill indicated,
>
> Type var = Type(istream_iterator<Type>(is),
> istream_iterator<Type>());
>
> would work, but it looks to me inefficient (is it?), since it creates
> two variables, initializes the anonymous one, then assigns it to the
> named one (right?)
This is correct. It is likely to be rather inefficient.
> I might stick to:
>
> Type var((istream_iterator<Type>(is)),
> istream_iterator<Type>());
>
> But what exactly is happening here?
The extra parenthesis remove the ambiguity between a declaration and a
definition: While 'X(is)' can be parsed as an argument for a function,
'(X(in))' cannot. Thus, the compiler has to parse the line as a
definition.
--
<mailto:dietmar.kuehl@claas-solutions.de>
homepage: <http://www.informatik.uni-konstanz.de/~kuehl>
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/11/03 Raw View
Jeet Sukumaran <jeet_sukumaran@my-deja.com> writes:
> I am still trying to figure out why the compiler is
> not confused by the second argument, and, for that matter, the logic
> behind the whole thing.
>
> Type var(istream_iterator<Type>(is),
> istream_iterator<Type>());
The compiler isn't confused by either argument. The declaration you
wrote can be parsed in two different ways, and the compiler chooses
one according to the dictates of the Standard. Your particular case
is sismilar to the example in 8.2/7.
Recasting to ints, we have
int var(int (is), int ());
The first argument can appear to be a parameter declaration with
redundant parentheses, i.e., equivalent to 'int is'.
The second argument can appear to be a parameter declaartion of a
function with an elided declarator, i.e., equivalent to 'int f()',
which in turn becomes equal to 'int (*f)()'.
So now we have a function declaration:
int var(int is, int (*f)());
The way to break the ambiguity is to make this interpretation
impossible. My suggestion was parentheses around the parameters,
since '(Type (/**/))' can not be parsed as a declaration.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jeet Sukumaran <jeet_sukumaran@my-deja.com>
Date: 1999/10/30 Raw View
Just when you think you that you understand at least certain aspects of
the language!
Wow! These C++ incantations can be quite devious at times!
Thanks a LOT people. As I mentioned to Valentin, this has been VERY
instructive for me, and I really appreciate y'all's patience and help
in this matter. I am still trying to figure out why the compiler is
not confused by the second argument, and, for that matter, the logic
behind the whole thing. Has it got to do with operator precedence?
With the function call operator() taking precedence over the
initialization operator()?
All in all, while I think that
Type var(istream_iterator<Type>(is),
istream_iterator<Type>());
would have been an elegant definition IF it did, in fact, define and
initialize a variable of Type, I think that
Type var(static_cast< istream_iterator<Type> >(is),
istream_iterator<Type>());
while actually doing the job, is too clumsy. As Bill indicated,
Type var = Type(istream_iterator<Type>(is),
istream_iterator<Type>());
would work, but it looks to me inefficient (is it?), since it creates
two variables, initializes the anonymous one, then assigns it to the
named one (right?)
I might stick to:
Type var((istream_iterator<Type>(is)),
istream_iterator<Type>());
But what exactly is happening here? Is this an old-style cast, or is
it a more legitimate statement, creating an anonymous istream_iterator
initialized to is?
Anyways, thanks again for all of your input. MUCH appreciated.
-- jeet
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Darin Adler <darin@bentspoon.com>
Date: 1999/10/30 Raw View
Jeet Sukumaran <jeet_sukumaran@my-deja.com> wrote:
> I might stick to:
>
> Type var((istream_iterator<Type>(is)),
> istream_iterator<Type>());
>
> But what exactly is happening here? Is this an old-style cast, or is
> it a more legitimate statement, creating an anonymous istream_iterator
> initialized to is?
It's a "more legitimate statement", not an old-style cast.
When converting y to type X, I call the following type conversion syntax an
old-style cast.
(X)y
The following type conversion syntax will do an old-style cast when X is a
non-class type (probably my least favorite C++ feature), but will call a
constructor when X is a class type.
X(y)
The following type conversion syntax can only be used to call a constructor,
because the language doesn't allow multiple expressions in a non-class type
conversion.
X(y, z)
Your example is like the third case above.
-- Darin
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]