1
\$\begingroup\$

I am writing a class that has a few std::string as a member. I can't find clear guidelines on how use them in a safe way. Are std::string any different then int when we are talking about class members? Do I initialize the strings in the correct way? (How) can I improve the constructor?

#include <string>
#include <iostream>

class Student {
public:
    std::string name;
    Student(std::string name) {
        this->name = name;
    }
};

int main() {
    std::string name1 = "john";
    Student student1(name1);
    name1 = "jenny";
    std::cout << student1.name << std::endl;
    {
        std::string name2 = "ashley";
        student1.name = name2;
        name2 = "remy";
    }
    std::cout << student1.name << std::endl;
    return 0;
}

Which gave the following output as intended:

john
ashley

\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

I am writing a class that has a few std::string as member. I can't find clear guidelines how use them in a safe way.

As long as you are not using new/delete their usage is by default safe.

Are std::string any different then int when we are talking about class members?

Any well constructed C++ class should behave just like a normal built in type (and everything in the standard is well constructed). As long as you don't use new/delete it should feel no different to you than using a built in type.

Do I initialize the strings in the correct way?

Its not going to break anything but it could be better.

(How) can I improve the constructor?

class Student {
public:
    std::string name;
    Student(std::string name) {
        this->name = name;
    }
};

Try not to use this->

This is a red flag.

  • You are either using it to be redundant
    Don't boither most C++ programers don't use it.
  • Or you need to use it to disambiguate local from member variables.
    If this is the case you are shadowing member variables which is dangerous. Turn on your compiler warnings and don't shadow variables as this will lead to situations where you accidentally use the wrong one.

Prefer to use the initializer list

All the members of a class are constructed before the body of the constructor is executed. So in your case you are constructing the name member then (in the body) calling the assignment operator. If you use the initializer list you construct the member using the parameter.

class Student {
public:
    std::string name;
    Student(std::string const& name)
        : name(name)
    {}
};

Move constructor

In the latest version of the standard we have introduced the concept of Move construction. This is advanced so ignore it for now if you are learning. But it allows for a more efficient form of construction (as the constructor above creates a copy of the input string), on the other hand the move constructor steals the content of the input parameter.

class Student {
public:
    std::string name;
    // Copy constructor
    Student(std::string const& name)
        : name(name)
    {}
    // Move constructor
    Student(std::string&& name)
        : name(std::forward<std::string>(name))
    {}
};
\$\endgroup\$
4
\$\begingroup\$

Consider replacing this:

Student(std::string name) {
    this->name = name;
}

with one of these two:

Student(std::string n)
: name{ std::move(n) } // assign here, not in function body
{
}

Student(const std::string& n)
: name(n) // assign here, not in function body
{
}

They are more efficient and more idiomatic.

The first takes the argument by value (constructs a string copy when it receives an argument) , then moves the constructed value into Student::name.

The second is marginally faster than the first (but this speed difference should not matter in most use cases, so which you choose is a matter of style), but it doesn't express as well as the first, the idea that Student gets it's own copy of the string (passing by value means "the function gets it's own copy of the value", or "the function takes ownership of the argument").

\$\endgroup\$
2
  • \$\begingroup\$ is it oke to do Student(const std::string& name) : name(name) {} Or is that considered unclear? \$\endgroup\$ Commented Apr 26, 2016 at 15:32
  • 1
    \$\begingroup\$ @martijnn2008: That is perfectly fine and considered very normal. \$\endgroup\$ Commented Apr 26, 2016 at 15:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.