Copy C'tor&Ass. op

Jul 30, 2013 at 3:48pm
I had this exercise during my lecture, The answer are in the comments,
I had 2 which I did not understand, and the question is showed in the comment.

1
2
3
4
5
6
7
8
9
10
int main () {
String s0(“abc”); //C'tor-Why not copy C'tor? 
String s1 = s0;  //copy C'tor
String s2(s0); //copy C'tor
String s3=“abc”; //copy C'tor, why not just a C'tor? I was told during the lecture
                 //that this is a char* and a copy C'tor gets string only.
                 //So how come I see the diffrence between the string and a char*?
String s4; //
s4 = s3;
return 1; }
Jul 30, 2013 at 4:34pm
The copy ctor is called when one object gets copied to another object.

Example:
String s1 = s0;

This is the copy ctor because 's0' is a String object, and it is being copied to 's1'.

On the other hand...
String s0(“abc”);

This is NOT the copy ctor because "abc" is not a String object... and therefore this is not an object->object copy... but instead it is constructing an object from a string literal. So this is calling the ctor which takes a const char* as a parameter.

String s3=“abc”; //copy C'tor, why not just a C'tor?

This is NOT the copy ctor, for the same reason the above was not a copy ctor. The correct answer here is the 'normal' const char* ctor.
Jul 30, 2013 at 5:17pm
The normal order of calling constructors in the following line

String s3=“abc”;

is the following. At first the constructor with the first parameter of const char * is called. It creates a temporary object of type String. When the move (if defined) or copy constructor is called to create named object s3 from this temporary object. So in fact two constructors, one with a parameter and the second either the move constructor or the copy constructor, are called.

However the C++ Standard allows to eliminate the call of the move or copy constructor Nevertheless the copy or move constructor shall be acceptable.

Consider the code

1
2
3
4
5
6
7
8
9
struct String
{
   String( const char * ) { std::cout << "String::String( const char * )" << std::endl; }

private:
   String( const String & ) { std::cout << String::String( const String & )" << std::endl;
};

String s3 = "abc"; 

This code shall not be compiled (except that MS VC++ 2010 contains a bug and will compile this code:) ) because the copy constructor is inaccessible though it wouldl not be called if it were public.
Last edited on Jul 30, 2013 at 5:19pm
Jul 30, 2013 at 9:07pm
How do I see the differences between a string a char*?
(How do I recognize each one of them?)

Vlad:
Why doesn't it call the Ass.op after converting the char* to a string?
Last edited on Jul 30, 2013 at 9:11pm
Jul 30, 2013 at 9:09pm
I have not understood the question.
Aug 2, 2013 at 5:28pm
1
2
 
String s3=“abc”; 

Why "abc" is a char* and not a string?

As you said, in this code-line we are calling 2 constructors:
1)The first C'tor which convert this char* to a string(what is the name of this C'tor?)
2)a copy C'tor to copy this converted string to s3(why are we now calling op= ??)


Last thing,
I do not understand how to implement a copy C'tor, can anyone give me an example?

Thanks
Aug 2, 2013 at 5:35pm
EDIT: Vlad is correct ... my understanding was wrong. Disregard this post


I'm pretty sure vlad is mistaken.

String s3=“abc”;

This calls exactly one constructor: String(const char*);. It does not call or involve the copy constructor in any way.

The copy constructor is only involved when you do a String->String copy. Here, you are not doing that, but rather are doing const char*->String.
Last edited on Aug 2, 2013 at 6:30pm
Aug 2, 2013 at 5:45pm
@Disch


I described all detailed. try the example I showed that is make the copy constructer private and the code will not be compiled. Or another example declare the copy constructor explicit and again the code will not be compiled.

1
2
3
4
5
6
7
8
9
struct String
{
   String( const char * ) { std::cout << "String::String( const char * )" << std::endl; }

private:
   String( const String & ) { std::cout << String::String( const String & )" << std::endl;
};

String s3 = "abc"; 


or

1
2
3
4
5
6
7
struct String
{
   String( const char * ) { std::cout << "String::String( const char * )" << std::endl; }
   explicit String( const String & ) { std::cout << String::String( const String & )" << std::endl;
};

String s3 = "abc"; 

The copy constructor must be accessible. The standard simply allows to eliminate the call of the copy constructor.
Aug 2, 2013 at 6:02pm
I can't try it now as the only compiler I have here is VS (which you already said it works on), but I would be very surprised if that were actually the case.

I had always been under the impression that String a = "foo"; and String a("foo"); were identical apart from the latter being explicit.

If you're right this draws into question this example:

1
2
3
4
5
6
7
8
void func( const String& a )
{
  ...
}

int main()
{
    func( "foo ");  // by your rationale, wouldn't this also call the copy ctor? 



This seems insane and wasteful to me... and I find it very hard to believe the standard dictates this. There is literally no reason for the temporary to be created in either case here.
Aug 2, 2013 at 6:19pm
You can try the example with function specifier explicit with using VC++.
Aug 2, 2013 at 6:26pm
> by your rationale, wouldn't this also call the copy ctor?
> This seems insane and wasteful to me... and I find it very hard to believe the standard dictates this.

It involves copy initialization (not copy construction).

1
2
3
4
5
6
7
String a("foo"); // direct initialization
// http://en.cppreference.com/w/cpp/language/direct_initialization

String a = "foo"; // copy initialization
// http://en.cppreference.com/w/cpp/language/copy_initialization

func( "foo" ); // copy initialization 



Aug 2, 2013 at 6:29pm
I stand corrected... and am completely flabbergasted.

That makes zero sense to me.
Aug 2, 2013 at 6:55pm
> and am completely flabbergasted.
> That makes zero sense to me.

Copy initialization is less permissive than direct initialization. That does not imply that it must be any less efficient than direct initialization.

In the above example, if there is no accessible non-explicit constructor, there would be a compile-time error. If there is one, there is no error, and the code generated is the same as in the case of direct initialization (the copy constructor is required to be accessible even though it's not used).
Last edited on Aug 2, 2013 at 6:55pm
Aug 3, 2013 at 10:17am
I do not understand your answers, could you try again please?
Aug 3, 2013 at 1:39pm
Why "abc" is a char* and not a string?

In the general sense of the word "string", it's a string. A char* is the basic way to handle strings in C. "abc" is a string literal, so therefore it's a char*.

But it's not a std::string. std::string is the STL string class. It's different from a char*, and is much more powerful (and safer) to use.

In C and C++, a string literal has the type char*, not std::string.

Edit: and I have no idea what the String type is that you have in your code, but I presume it's another class that implements a string, and so is different again from both std::string and char*.
Last edited on Aug 3, 2013 at 1:41pm
Aug 3, 2013 at 2:22pm
@IrarI
Vlad:
Why doesn't it call the Ass.op after converting the char* to a string?


The copy assignment operator is applied to already created objects. When an object is being created a copy constructor is used. Compare.

String s1;

String s2 = s1; // the copy constructor is used

String s3;
s3 = s1; // the copy assignment operator is used.
Topic archived. No new replies allowed.