views:

233

answers:

4

Hi.

I often see the following structure, especially in constructors:

class::class(const string &filename)
{
}


class::class(const char * const filename)
{
}

By step-by-step debug, I found out the 2nd constructor is always called if I pass a hard-coded string.

Any idea:

1) Why the dual structure is used?

2) What is the speed difference?

Thanks.

A: 

1) Why the dual structure is used?

The string reference version is required if std::string objects are to be used conveniently as parametersm as there is no implicit conversion from a std::string to a const char const. The const char * const version is optional, as character arrays can implicitly be converted into std::strings, but it is more efficient, as no temporary std::string need be created.

2) What is the speed difference?

You will need to measure that yourself.

anon
A: 

They are offered basically for convenience. Some times, if you call C functions, you get char* pointers. Others, you get strings, so offering both constructors is just a convenience for the caller. As for the speed, both have virtually the same speed, as they both send a memory address to the constructor.

Diego Sevilla
Same speed? Even if the constructor taking the string does contact a with a remote repository and downloads a chinese translation of War and Peace via Google Translation API via the repository, and the char* constructor just assigns a value? :P
Kornel Kisielewicz
If the original string is a C++ string, performance will be the same. If the original string is a C-style string (or a literal), then having only the std::string version will require creation of a temporary. My advice would be using C++ strings whenever necessary, but if you find a bottleneck in performance consider adding the extra C-style overload.
David Rodríguez - dribeas
+1  A: 

This is useful if the implementation deals with const char*s by itself, but is mostly called by std::string users. These can call using the std::string API, which usually just calls c_str() and dispatches to the const char* implementation. On the other side, if the caller does already have a c-string, no temporary or unneeded std::string needs to be constructed (which can be costly, for longer strings it's a heap allocation).

Also, I once used it to resolve the following case:

My interface took std::string's, but had to be implemented in an external module, thus the STL binary versions of both the module AND the caller module had to match exactly, or it would have crashed (not really good for a portable library… ). So I changed the actual interface to use const char*, and added std::string overloads which I declared inline, so they weren't exported. It didn't break existing code, but resolved all my module boundary problems.

Alexander Gessler
+3  A: 

Two constructors are needed because you can pass a NULL to your MyClass::MyClass(const std::string &arg). Providing second constructor saves you from a silly crash.

For example, you write constructor for your class, and make it take a const std::string & so that you don't have to check any pointers to be valid if you'd be using const char*. And everywhere in your code you're just using std::strings. At some point you (or another programmer) pass there a const char*. Here comes nice part of std::string - it has a constructor, which takes char*, and that's very good, apart from the fact, that std::string a_string(NULL) compiles without any problems, just doesn't work.

That's where a second constructor like you've shown comes handy:

MyClass::MyClass(const char* arg)
    : m_string(arg ? arg : "")
{}

and it will make a valid std::string object if you pass it a NULL.

In this case I don't think you'd need to worry about any speed. You could try measuring, although I'm afraid you'd be surprised with how little difference (if any) there would be.

EDIT: Just tried std::string a_string(NULL);, compiles just fine, and here's what happens when it is run on my machine (OS X + gcc 4.2.1) (I do recall I tried it on Windows some time ago, result was very similar if not exactly same):

std::logic_error: basic_string::_S_construct NULL not valid

Dmitry
Thanks, this clarifies the matter!
SyBer