Explicit copy constructor
Asked Answered
H

3

24

I have extended std::string to fulfil my needs of having to write custom function build into string class called CustomString

I have defined constructors:

    class CustomString : public std::string {
    public:
        explicit CustomString(void);
        explicit CustomString(const std::string& str);
        explicit CustomString(const CustomString& customString);
        //assignment operator
        CustomString& operator=(const CustomString& customString);
    ... };

In the third constructor (copy constructor) and assignment operator, whose definition is:

CustomString::CustomString(const CustomString& customString):
    std::string(static_cast<std::string>(customString)) 
{}
CustomString& CustomString::operator=(const CustomString& customString){
    this->assign(static_cast<std::string>(customString));
    return *this;
}

First since this is an "explicit"; meaning an explicit cast is needed to assign to another CustomString object; it's complaining about the assignment.

CustomString s = CustomString("test");

I am not sure where exactly is casting needed explicitly.

The code works alright if copy constructor is not explicit but I would like to know and implement explicit definition instead of "guessing proper cast".

Hammett answered 14/7, 2012 at 2:29 Comment(0)
P
50

The explicit copy constructor means that the copy constructor will not be called implicitly, which is what happens in the expression:

CustomString s = CustomString("test");

This expression literally means: create a temporary CustomString using the constructor that takes a const char*. Implicitly call the copy constructor of CustomString to copy from that temporary into s.

Now, if the code was correct (i.e. if the copy constructor was not explicit), the compiler would avoid the creation of the temporary and elide the copy by constructing s directly with the string literal. But the compiler must still check that the construction can be done and fails there.

You can call the copy constructor explicitly:

CustomString s( CustomString("test") );

But I would recommend that you avoid the temporary altogether and just create s with the const char*:

CustomString s( "test" );

Which is what the compiler would do anyway...

Pinnatipartite answered 14/7, 2012 at 2:57 Comment(4)
Oh yea I completely understand your answer (and it is proper answer and I have marked it as best answer) but how would I achieve CustomString s = customStringObjectOnStack; for example?Hammett
@mkhan3189 you can achieve CustomString s = customStringObjectOnStack if and only if copy-ctor will not be explicit. For second question, kDelimited is CustomString or something else? And + your function is const, so c.append(static_cast<const std::string&>(*this)) will works.Slushy
@Slushy Yea Thanks for that. I got the answer myself. kDelimiter is CustomString constant object, yes. c.append(static_cast<std::string>(*this)) works for implicit copy-ctor declaration. So all good. This thread can be closed.Hammett
@mkhan3189: You can achieve CustomString s = customStringObjectOnStack; by instead of implicitly using that copy constructor with the = syntax, you explicitly call the copy constructor: CustomString s( customStringObjectOnStack );Comehither
S
7

Deriving from std::string is not safe, as std::string has no virtual destructor. As to your question - your copy constructors should not be explicit, to allow for such usage as:

CustomString s = "test";

Also I have no idea why you would want to declare a copy-constructor as explicit, as it is not needed. An explicit copy-constructor will work only if you declare your CustomString object as:

CustomString s(CustomString("test"));
Slushy answered 14/7, 2012 at 2:32 Comment(5)
@ildjarn: why lazy? It is correct (not optimal, but correct) tackles the problem and provides a solution...Comehither
@DavidRodríguez-dribeas when ildjarn posting comment, answer was rather shorter.Slushy
Thanks and nice answer but this is lazy because I have asked this to improve my way of writing code instead of just getting thing done. Thanks anyways :)Hammett
As long as the OP only uses CustomStrings and doesn't, say, try to delete a new CustomString through a std::string pointer, is there really anything unsafe about this derivation?Lusatia
“As long as [...], is there anything unsafe?”. Unless you have the means to enforce the conditions reliably and consistently over time, including coworker's code and wherever this might get copy-pasted to in the future, the answer to that question is always yes. No matter what's in the "[...]".Incorporate
A
0

It seems current gcc won't invoke the copy constructor tested in gcc 8.2(MinGW.org GCC-8.2.0-5),and will utilize to call constructor directly For X1

#include <iostream>

using std::cout;
using std::endl;


class X1 {
public:

    X1() {
        cout<< "invoke constructor" << endl;
    }; 

    explicit X1(const X1 &obj)  { 
        cout << "invoke copy constructor" << endl;
    };

    X1(X1&& obj)  {
        cout << "invoke move constructor" << endl;
    };

    X1& operator=(const X1 &obj) {
        cout << "invoke value assign constructor " << endl;
        if(this == &obj) {
            return *this;
        }
        return *this;
    };

    X1& operator=(const X1 && obj) {
        cout << "invoke move value assign constructor " << endl;
        if(this == &obj) {
            return *this;
        }
        return *this;

    };

    ~X1() {
        cout << "invoke deconstruct" << endl;
    };



};

int main() {
//    X1 l1(1);
//    X1 l3(2);
    X1 l4 = X1();

    return 0;
}
Ackley answered 25/4, 2022 at 2:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.