Is there empty std::string defined somewhere?
What I mean is following:
I can do:
// code #1
int process(const char *s = nullptr);
// later I can use:
process();
However, if I do:
// code #2
int process(const std::string &s = "");
// later I can use:
process(); // wait, an object is created...
It compiles and works, when I use the function, there is unneeded object creation.
Is there standard way to do following:
// code #3
const std::string EMPTY_STR;
int process(const std::string &s = EMPTY_STR);
// later I can use:
process(); // fine, no object is created...
This is not bottleneck, nor it is a premature optimization.
I believe C++ is not Java, so right way is not to create objects that you do not need.
Also I believe code 3 looks much better than code 2 and also it show the intention that string is empty (and probably will not be used), than code 2, where is not very clear why the string is "".
There's no (safe) way of making a reference refer to nothing. If you don't want an object to be created at all, you have to use a pointer;
int process(const std::string *s = nullptr);
If you want to use references, there must be an object somewhere. For that purpose, you could use a default-constructed (empty) string as default argument;
int process(const std::string& s = std::string());
First of all, I am slightly surprised you need an OBJECT. It is going to be a const object anyway, so what does it give you which simple const char* does not?
Second, there is a solution to your problem in a generic way. There is a genuine problem with following omnipresent code:
void foo(const std::string& data);
It allows using foo with both std::strings and const char*, and suits almost everybody. It does not matter for majority of users of foo(), but for someone really fixed on performance (as in nanoseconds) creation of temporary std::string from their const char* is a sore point. To solve this problem, StringRef was invented. It is not available in std, but it exits in many libraries including boost, and is simple to implement. The idea is following:
class StringRef {
...
StringRef(const std::string& str) : b(str.begin()), end(str.end()) {}
StringRef(const char* str) : b(str), end(str + strlen(str)) {}
...
private:
const char* const b;
const char* const e;
};
void foo(const StringRef str);
Related
I found this code in a C++ header-only wrapper around a C API I'm working with:
static string GetString(const char* chString)
{
string strValue;
if (NULL != chString)
{
strValue.swap(string (chString));
releaseMemory((void*&)chString);
chString = NULL;
}
return strValue;
}
I suppose the author is trying to give the string strValue ownership of chString and then free the empty buffer. I suspect this is very wrong (including it being const char*), but it actually seems to work with MSVC 12. At least I haven't seen it crash spectacularly yet.
Assuming that the C API and the C++ library are using the same heap (so that the string can reallocate the buffer if necessary and eventually release it), is there a way to properly achieve this? How about this?
template <typename T> struct Deleter { void operator()(T o) { releaseMemory((void*&)o); } };
static std::string GetString(char* chString)
{
if (NULL == chString)
return std::string();
return std::string(std::unique_ptr<char[], Deleter<char[]>>(chString).get());
}
Again, assuming the C API is using the same heap as std::string.
If that's also very wrong, then is there an immutable, owning C-style string wrapper? Something like string_view but immutable (so const char* input would be ok) and owning (so it deletes the C string, possibly with a custom deleter, in its dtor)?
I suppose the author is trying to give the string strValue ownership of chString and then free the empty buffer.
No. It makes an (inefficient and error-prone) copy of the character data pointed to by chString, then releases the memory pointed to by chString (which will be skipped if the copy throws an exception), and then returns the copy.
Assuming that the C API and the C++ library are using the same heap
That is not a correct assumption, or even a necessary one. The copy can use whatever heap it wants.
is there a way to properly achieve this? How about this?
You are on the right track to use a std::unique_ptr with a custom deleter, but there is no reason to use the T[] array specialization of std::unique_ptr.
The code can be simplified to something more like this:
void Deleter(char* o) { releaseMemory((void*&)o); }
static std::string GetString(char* chString)
{
std::string strValue;
if (chString) {
std::unique_ptr<char, decltype(&Deleter)>(chString, &Deleter);
strValue = chString;
}
return strValue;
}
Or, just get rid of the check for chString being null, it is not actually needed. std::string can be constructed from a null char*, and std::unique_ptr will not call its deleter with a null pointer:
void Deleter(char* o) { releaseMemory((void*&)o); }
static std::string GetString(char* chString)
{
std::unique_ptr<char, decltype(&Deleter)>(chString, &Deleter);
return std::string(chString);
}
Does this seem like a good solution for my last question (and ultimate goal of being able to use a char* like a string without copying it)?
template <typename DeleterT = std::default_delete<const char*>>
class c_str_view
{
public:
unique_ptr<const char*, DeleterT> strPtr_;
size_t len_;
c_str_view() {}
c_str_view(const char* charPtr) : strPtr_(charPtr), len_(strlen(charPtr)) {}
c_str_view(const char* charPtr, size_t len) : strPtr_(charPtr), len_(len) {}
operator std::string_view () const
{
return string_view(strPtr_.get(), len_);
}
};
If so, is there a good reason this isn't in the upcoming standard since string_view is coming? It only makes sense with string_view of course, since any conversion to std::string would cause a copy and make the whole exercise pointless.
Here's a test:
http://coliru.stacked-crooked.com/a/9046eb22b10a1d87
I am not sure that I am using the right terminology, but question is how do I properly make a constructor that takes a string in as a parameter?
I am used to having a const char * in the constructor instead of strings.
Normally I would do something like this:
Name(const char* fName, const char* lName)
: firstName(0), lastName(0)
{
char * temp = new char [strlen(fName) + 1];
strcpy_s(temp, strlen(fName) + 1, fName);
firstName = temp;
char * temp2 = new char [strlen(lName) + 1];
strcpy_s(temp2, strlen(lName) + 1, lName);
lastName = temp2;
}
What if the constructor is this:
Name(const string fName, const string lName) { }
Do I still do base member initialization? do I still need to use string copy in the base of the constructor?
Use std::string and initializer lists:
std::string fName, lName;
Name(string fName, string lName):fName(std::move(fName)), lName(std::move(lName))
{
}
In this case, you don't need to use terribly bare pointers, you don't need allocate memory, copy characters and finally de-allocate. In addition, this new code has chances to take advantages of moving rather than copying since std::string is movable. Also it's useful to read this.
And so on....
I see that you have already accepted an answer but I would like to expand upon the answers.
As deepmax said, if you pass by value you can write your constructor to take advantage of "move semantics". This means instead of copying data, it can be moved from one variable to another.
Written like so:
class Name{
public:
Name(std::string var): mem_var(std::move(var)){}
std::string mem_var;
};
Which seems like a good idea, but in reality is no more efficient than the copy constructor
class Name{
public:
Name(const std::string &var): mem_var(var){}
std::string mem_var;
};
The reason this is, is because in the general use case that looks like this:
auto main() -> int{
Name name("Sample Text");
}
only one copy will ever get made either way (see copy elision), and in the other case of
auto main() -> int{
std::string myname = "Hugh Jaynus";
Name name(myname);
}
2 copies will be made in the 'efficient' pass-by-value move semantics way!
This is a good example of when the copy constructor (or pass-by-reference) should be used, not an example against it.
On the contrary...
If you write an explicit constructor that makes use of move semantics you could get an efficient solution no matter the circumstance.
Here is how you might write out a name class definition with both constructors:
class Name{
public:
Name(const std::string &first_, const std::string &last_)
: first(first_), last(last_){}
Name(std::string &&first_, std::string &&last_) // rvalue reference
: first(std::move(first_)), last(std::move(last_)){}
std::string first, last;
};
Then when you use the class the more efficient path should be taken.
If we go back to our examples we can rewrite them to make use of the best or most efficient constructor:
int main(){
// pass by reference best here
Name myname("Yolo", "Swaggins");
// move most efficient here
// but never use 'first' and 'last' again or UB!
std::string first = "Hugh", last = "Jaynus";
Name yourname(std::move(first), std::move(last));
}
Never just take for granted that one solution is better than all others!
I'm used to do this:
std::string fName;
std::string lName;
Name(const std::string &fName, const std::string &lName) :
fName(fName), lName(lName)
{
}
Using the references saves the work of copying the strings to a new object on the stack, it will just pass the reference to the existing string. Once you are assigning them to the class members, they will get copied.
if you want to keep const char * as your constructor input types do this.
std::string fName;
std::string lName;
Name(const char *_fName, const char *_lName) :
fName(_fName), lName(_lName)
{
}
You can construct a std::string from a const char.
I'm new to and learning C++. I know a fair amount of Java and some C.
What I want to do is to create an immutable name class that takes in a string value, copies that string to a class field and then eventually hashes it to an ID that can be parsed much more efficiently than a string.
I'm hitting a wall due to a general lack of knowledge of C++ strings. Here's what I have so far...
#pragma once
#include <string>
class Name
{
public:
Name(std::string s);
~Name(void);
int getId();
std::string getName();
private:
int id;
std::string name;
};
and...
#include "Name.h"
Name::Name(std::string s)
{
}
So what I want to do is store the value of s, passed in by the constructor in the "name" private field. As far as I know a new string object must be created and then the value of s must be copied into it.
I also think that the argument s can and should be a string pointer instead of a string object (to prevent an unnecessary copy from occurring). If I'm right then the constructor should look like the following, right?
Name::Name(std::string &s) { ... }
In this case, nothing would need to be done special when passing in a name? IE.
Name n = new Name("Cody");
is perfectly valid? Actually I'm not sure since "Cody" to my knowledge is a constant string or something like that.
So if I'm all on the right track, then what is the proper way to actually copy the value? I'm thinking this is appropriate but I'm not sure.
#include "Name.h"
Name::Name(std::string s)
{
name = new string(s);
}
Thanks for the help in advance, I know it's a basic question but I'm slowly making baby steps into the C++ world. :) - Cody
You are close, your code can be like this after a little massage:
class Name
{
public:
Name(const std::string& s); // add const and reference
~Name(void);
int getId() cosnt; // add const
std::string getName() const; // add const
private:
int id;
std::string name;
};
Name.cpp
Name::Name(const std::string& s):name(s)
{
}
Here :name(s) is called member initializer list.
Name n = new Name("Cody"); is perfectly valid? Actually I'm not sure
since "Cody" to my knowledge is a constant string or something like
that.
No, n is not pointer, it's not like java you need to new for every object. In C++, you do
Name n("Cody");
This will call Name(const std::string& s) to initialize object n and initialize name string with "Cody".
Note: variable n has automatic storage duration, it will be destroyed if it goes out of scope.
To let n on dynamic storage duration, you need to use new/delete pair:
Name *pn = new Name("Cody");
delete pn;
or use smart pointers, you no need to call delete n_ptr; as n_ptr will be destroyed when it goes out of scope as well:
#include <memory>
std::shared_ptr<Name> n_ptr(new Name("Cody"));
EDIT:
To use Name class in other classes, it's the same way when you use string in Name class, you don't have to use pointers.
class TestName
{
public:
TestName(const Name& n):name_(n){ }
private:
Name name_;
};
TestName tn("Cody");
You should use a constant reference to std::string here.
As you said, it would prevent unnecessary copies.. But then why not just a pointer or a constant pointer?
A constant reference would allow you to pass to your function some arguments that would implicitly call the right std::string constructor.
So, in a nutshell, you could do that:
Name::Name(const std::string& s)
{
this->name = s;
}
// Or even better..
Name::Name(const std::string& s):
name(s)
{
}
int main(void)
{
Name nick("hello");
return 0;
}
You can find out about every std::string's constructors on its cplusplus.com's sheet.
I am modifying a function that accepts a const char* and uses a function, ProcessString. ProcessString is a function that expects a null-terminated character buffer as a char*. The characters in the buffer may or may not be modified, as defined by the function signature below. To "bridge the gap", I am using a temporary std::string:
void ProcessString( char* str );
void SomeFunction( const char* str )
{
string temp(str);
ProcessString( &temp[0] );
}
My primary question is about the guarantees of std::string::operator[] and whether the address returned by the &temp[0] above is a usable, null-terminated buffer as a char*. Secondly, and very much secondly, is there a better way to do this?
I am using C++03.
That only has well-defined behavior in C++11; in previous standards, std::string did not guarantee contiguous storage for its internal buffer.
However while that code is completely fine in C++11, the more idiomatic approach is to use std:vector<char>, which has guaranteed contiguous storage since C++03:
void ProcessString(char* str);
void SomeFunction(char const* str)
{
// + 1 for terminating NUL
std::vector<char> temp(str, str + std::strlen(str) + 1);
ProcessString(&temp[0]); // or temp.data() in C++11
}
I have created a small class to face this kind of problem, I have implemented the RAII idiom.
class DeepString
{
DeepString(const DeepString& other);
DeepString& operator=(const DeepString& other);
char* internal_;
public:
explicit DeepString( const string& toCopy):
internal_(new char[toCopy.size()+1])
{
strcpy(internal_,toCopy.c_str());
}
~DeepString() { delete[] internal_; }
char* str() const { return internal_; }
const char* c_str() const { return internal_; }
};
And you can use it as:
void aFunctionAPI(char* input);
// other stuff
aFunctionAPI("Foo"); //this call is not safe. if the function modified the
//literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string
//implement reference counting and
//it may change the value of other
//strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine
I have called the class DeepString because it is creating a deep and unique copy (the DeepString is not copyable) of an existing string.
If you need to go from a const char* to a char *, why not use strdup, and then free the buffer when ProcessString is done?
Going through std::string seems unnecessary to me.
In the ArduinoUnit unit testing library I have provided a mechanism for giving a TestSuite a name. A user of the library can write the following:
TestSuite suite("my test suite");
// ...
suite.run(); // Suite name is used here
This is the expected usage - the name of the TestSuite is a string literal. However to prevent hard-to-find bugs I feel obliged to cater for different usages, for example:
char* name = (char*) malloc(14);
strcpy(name, "my test suite");
TestSuite suite(name);
free(name);
// ...
suite.run(); // Suite name is used here
As such I have implemented TestSuite like this:
class TestSuite {
public:
TestSuite(const char* name) {
name_ = (char*) malloc(strlen(name) + 1);
strcpy(name_, name);
}
~TestSuite() {
free(name_);
}
private:
char* name_;
};
Putting aside the issue of failing to deal with memory allocation failures in the constructor I'd prefer to simply allocate the pointer to a member variable like this:
class TestSuite {
public:
TestSuite(const char* name) : name_(name) {
}
private:
const char* name_;
};
Is there any way I can change the interface to force it to be used 'correctly' so that I can do away with the dynamic memory allocation?
What if you provide two overloaded constructors?
TestSuite(const char* name) ...
TestSuite(char* name) ...
If called with a const char*, then the constructor could make a copy of the pointer, assuming that the string will not go away. If called with a char*, the constructor could make a copy of the whole string.
Note that it is still possible to subvert this mechanism by passing a const char* to the constructor when the name is in fact dynamically allocated. However, this may be sufficient for your purposes.
I should note that I have never actually seen this technique used in an API, it was just a thought that occurred to me as I was reading your question.
Documentation. For example,
/**
* Test suite constructor.
* #param name test suite name cstring, shared
*/
TestSuite(char const *name) {
// ...
A shared pointer implies that the pointed object must be alive during the lifetime of this object.
Well, you can use a std::string that will take care of all memory allocation
class TestSuite {
public:
TestSuite(const std::string &name):name_(name) {
}
~TestSuite() {
}
private:
std::string name_;
};
Edit :
If it is the call to malloc() that you want to avoid you could do this :
class TestSuite {
public:
TestSuite(const char *name){
memcpy(name_, name, min(16, strlen(name));
}
private:
char name_[16];
};
This will waste some memory however, which can be an issue on embedded platforms.
Have a char name[XYZ] member of your TestSuite (with an XYZ large enough to comfortably display the name) and use strncpy to copy the string (with a maximum length of XYZ-1).
Why are you using char* and malloc when you have the nice C++ string class which can takes a string literal or a char* in its constructor ?
Are you able to use std::string? You could have it as std::string name_ and have the STL take care of the memory allocation for you..
class TestSuite {
public:
TestSuite(const char* name) : name_(name) {}
~TestSuite() {}
private:
std::string name_;
};
Don't forget to include <string>.
Reference