copy initialization and direct initialization from C++ Primer

P

pauldepstein

From page 477 of 4th edition of C++ Primer.
"Direct-initialization directly invokes the constructor matched by the
arguments. Copy-initialization always involves the copy-constructor."

It occurs to me that the "constructor matched by the arguments" might
be the copy-constructor. In this case, I would think copy-
initialization and direct-initialization are exactly the same. My
concern (and reason for this posting) is that I haven't seen anyone
say the same thing.

For example, does std::string null_book = "99"; mean the same
as std::string null_book("99"); ? (On my compiler, they behave the
same way.) And would the behaviour always be the same if std::string
is replaced by another class?

Paul Epstein
 
V

Victor Bazarov

From page 477 of 4th edition of C++ Primer.
"Direct-initialization directly invokes the constructor matched by the
arguments. Copy-initialization always involves the copy-constructor."

It occurs to me that the "constructor matched by the arguments" might
be the copy-constructor. In this case, I would think copy-
initialization and direct-initialization are exactly the same. My
concern (and reason for this posting) is that I haven't seen anyone
say the same thing.

You're just picking on words, aren't you? If the constructor "matched
by the arguments" is the copy-constructor, then the initialisation is in
fact *copy-initialisation*, isn't it?
For example, does std::string null_book = "99"; mean the same
as std::string null_book("99"); ?

No. The former is copy-initialisation. The array "99" degrades to the
pointer to its first character, and then a temporary is constructed,
from which the 'null_book' is constructed. So, 'null_book' is
copy-initialised (in this case). Those are the semantics, anyway. The
compiler is *allowed* to skip creating the temporary in that case, but
the copy constructor has to be *accessible*, *as if* the copy is
actually created.
> (On my compiler, they behave the
same way.) And would the behaviour always be the same if std::string
is replaced by another class?

Yes. For example,

class my_noncopyable_string {
my_noncopyable_string(const my_noncopyable_string&); // private
public:
my_noncopyable_string(const char*);
};

int main() {
my_noncopyable_string foo = "99";
}

shouldn't compile, but

...
my_noncopyable_string bar("99");

should.

V
 
A

Andrey Tarasevich

From page 477 of 4th edition of C++ Primer.
"Direct-initialization directly invokes the constructor matched by the
arguments. Copy-initialization always involves the copy-constructor."

It occurs to me that the "constructor matched by the arguments" might
be the copy-constructor. In this case, I would think copy-
initialization and direct-initialization are exactly the same. My
concern (and reason for this posting) is that I haven't seen anyone
say the same thing.

Well, I believe it has been said here many times. According to the
language specification, when the object type and the initializer type
are the same (ignoring any CV-qualification), both initializations works
in exactly the same way (is copy-initialization follows exactly the same
algorithm as direct-initialization).
For example, does std::string null_book = "99"; mean the same
as std::string null_book("99"); ?

No, of course not. But what does this have to do with your original
question? Your question was about situation when copy constructor is
selected by direct-initialization. In this example direct-initialization
_does_ _not_ select copy constructor. Instead, it will use conversion
constructor from 'const char*'. So, what is this example is doing here?
(On my compiler, they behave the same way.)

I'm not sure what you mean by "the same" here, but if they indeed behave
exactly the same way, this might be the effect of compiler optimization.
From the abstract C++ point of view the first version calls copy
constructor (just like you said above), while the second does not. I.e.
they don't behave the same way.
And would the behaviour always be the same if std::string
is replaced by another class?

It is hard to understand what you are trying to ask, since the example
you are referring to does not match the original question you were
asking. Please, clarify your question.
 
J

James Kanze

From page 477 of 4th edition of C++ Primer.
"Direct-initialization directly invokes the constructor
matched by the arguments. Copy-initialization always involves
the copy-constructor."
It occurs to me that the "constructor matched by the
arguments" might be the copy-constructor. In this case, I
would think copy- initialization and direct-initialization are
exactly the same. My concern (and reason for this posting) is
that I haven't seen anyone say the same thing.

The distinction between copy-initialization and
direct-initialization is one of syntax:
T v = x ;
is copy initialization,
T v( x ) ;
is direct initialization, regardless of what constructors
ultimately get called. The standard does distinguish the case
where the initializing type in copy initialization has the same
type (modulo cv-qualifiers) as the type being initialized, in
order to make it clear that the copy constructor can't be called
twice. The basic rules are: direct initialization and copy
initialization where the type of the initializing expression is
the same as that of the initialized object: find an appropriate
constructor and call it; copy initialization where the
initialization expression has a different type, convert that
type to the target type, then find an appropriate constructor
(using operator overload resolution---and there are cases where
the appropriate constructor won't be the copy constructor) and
call it.
For example, does std::string null_book = "99"; mean the same
as std::string null_book("99"); ?

The final results will be the same, because of the semantics of
std::string. Formally, however, the first is the equivalent of:

std::string null_book( std::string( "99" ) ) ;

The compiler is allowed to optimize the intermediate temporary
out, but only if the program would be legal before the
optimization.
(On my compiler, they behave the same way.) And would the
behaviour always be the same if std::string is replaced by
another class?

For most classes, you won't see a difference. Provide a private
copy constructor, and copy initialization will cause an error at
compile time. Provide a conversion operator in the
initialization type, but no constructor using that type in the
target type, and copy initialization will be legal, but not
direct initialization.
 
J

James Kanze

You're just picking on words, aren't you? If the constructor
"matched by the arguments" is the copy-constructor, then the
initialisation is in fact *copy-initialisation*, isn't it?

No. Copy initialization refers to the syntax, not which
constructor is called.

If you really want to pick on words: the copy constructor has
nothing to do with anything here. The only particularity of the
copy constructor is that the compiler will generate one if the
programmer doesn't declare one. The signature of the copy
constructor is such that it will often be chosen by overload
resolution when copying (whence the name), but formally, it has
no special role here---the compiler applies overload resolution,
as usual.
No. The former is copy-initialisation. The array "99"
degrades to the pointer to its first character, and then a
temporary is constructed, from which the 'null_book' is
constructed. So, 'null_book' is copy-initialised (in this
case). Those are the semantics, anyway. The compiler is
*allowed* to skip creating the temporary in that case, but the
copy constructor has to be *accessible*, *as if* the copy is
actually created.

And the semantics of std::string are such that you can't tell
whether the compiler has skipped the temporary or not, so
ultimately, the two do mean the same thing.
Yes. For example,

You mean no, of course (since you give an example where the
behavior isn't the same).
 
A

Arne Mertz

James said:
For most classes, you won't see a difference. Provide a private
copy constructor, and copy initialization will cause an error at
compile time. Provide a conversion operator in the
initialization type, but no constructor using that type in the
target type, and copy initialization will be legal, but not
direct initialization.

Yes, direct initialization _will_ be legal. As with the call of any
normal function the compiler will try to implicitly convert the
argument in another type that fits the function's (i.e. the
constructor's) parameter.

greets
Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top