I have a class like that.I want to use reference for string but it doesnt work.How can i use string& ?
#include <string>
using namespace std;
class T
{
public:
T(string& s);
private:
string s;
};
T::T(string& s)
{
this->s = s;
}
int main(void)
{
T t("Test Object");
return 0;
}
Error : 'T::T(std::string &)' : cannot convert parameter 1 from 'const char [12]' to 'std::string &'
Use const :
class T
{
public:
T(const string& ss);
private:
string s;
};
T::T(const string& ss) : s(ss)
{
}
"Test Object" will be constructed as a const string before passing to T's constructor, so the constructor has to accept a const string.
You're not passing in a std::string. As it says, it can't convert from const char array to string-ref. Change the constructor to take a const-ref and it'll work. This is because a temporary string will have to be created from the char-array, and you can only make const-references to temporaries to stop you getting confused (if you modify the temporary, the changes are just going to be discarded, so the language stops you from doing that).
In C++98/03, if you have a class that is not cheap to copy (e.g. an int or a double are cheap to copy, a std::string isn't, since its copy can involve allocating new heap memory, copying characters from source to destination, etc.), then the rule is to pass by const reference const std::string&:
class T
{
public:
T(const string& s); // <--- const string&
private:
string m_s;
};
And then in constructor do:
T::T(const string& s)
: m_s(s)
{}
However, in C++11, where move semantics is available, the new rule seems to be: if you need a copy (and the object is cheap to move, as it normally should be), pass by value and move from the value:
T::T(string s) // pass by value
: m_s( std::move(s) ) // and move from the value
{}
(The optimal thing would be to offer a couple of overloads, passing by const & and passing by value, but probably this is not necessarily in all applications, but only when you need to squeeze performance.)
Note that when you don't need a copy, and just need to observe the parameter, the usual C++98/03 pass by const & rule is still valid.
The constructor you defined takes a std::string by reference:
T::T(std::string& s)
{
this->s = s;
}
thus the most straightforward thing to do would be to create a std::string object, that will be passed to this constructor:
std::string s("Test Object");
T t(s);
But since your constructor doesn't change the std::string you pass to it (it is just used to set the value of T's data member) you should pass const reference: T::T(const string& s). Also instead of letting the data member s being constructed and assigning another string into it later, it would be better if you construct this member directly within an initialization list:
T::T(const std::string& str) : s(str) { }
References need to be intialized using the initialiser-list of the constructor. Change your constructor to:
T::T(string& s) : s(s)
{
}
Additionally define your member s as std::string& s to be able to take a reference.
Maybe change the name of s to avoid ambiguities.
See this entry on SO.
Related
I don't understand, If I pass a string by ref. to a function then the address of actual string passed will be same as that of formal string in this function. Any changes to either will impact on either of the two. But it is not same for passing string by ref. to a class ctor. Why is that? Although I do understand, different objects must have different addresses.
Class Abc
{
private:
std::string s;
public:
Abc(std::string str)
: s(str)
{}
};
void fun(std::string& str)
{ str [0]='i';} // changes content in st
int main()
{
std::string st = "hello";
Abc obj(st);
//if we change st shouldn't it change s in obj
st[0] = 'j';
fun(st);
}
Your member variable std::string s; is not a reference, it's a plain string. So when you initialize it it gets constructed by copying the string you initialize it with.
You are copying the string by value in the constructor.
This is how you would store the reference:
class Abc{
std::string& str;
public:
Abc(std::string& s): str(s){}
};
void foo(){
std::string str;
Abc abc(str);
str = ”Hello World”;
/// abc.str is now also hello world
}
But now, beware about lifetimes!
By passing the object by reference to the object in the constructor, the lifetime is not extended, meaning when str goes out of scope, abc.str points to invalid memory -> undefined behavior.
C++, unlike other languages such as python is a value-based language as in that assignments copy by default unless you do extra tricks like move, taking the address or taking a reference (which is a similar thing to taking the address).
In your example, you're not passing the string as a reference to the constructor.
Abc(std::string str)
should be
Abc(std::string& str)
If you want the value change of the original string to reflect into the member variable in class(or the other way around). Then you need to make member variable as reference. Your class should look like
Class Abc
{
private:
std::string& s;
public:
Abc(std::string& str)
: s(str)
{}
};
I have a constructor that accepts a const reference to a std::string object and is supposed to store the std::string's internal C string in a void pointer member variable. However, my program segfaults when the void pointer is used, and gdb says that the pointer is pointing to address 0x01. Here is my source:
Foo.h:
class Foo {
public:
Foo(const std::string& str);
void* getData();
private:
Foo(void* newData);
void* data;
};
Foo.cpp:
Foo::Foo(const std::string& str)
: Foo(str.c_str())
{
//nothing
}
void* Foo::getData() {
return data;
}
Foo::Foo(void* newData)
: data(newData)
{
//nothing
}
main.cpp:
int func(void* data);
int main() {
Foo f("bar");
func(f.getData()); //segfault here
return 0;
}
int func(void* data) {
std::string str = (char*)data;
std::cout << str << std::endl;
return 0;
}
The string that is constructed from "bar" no longer exists when you call f.getData(), so the pointer to its internal character array is no longer valid. The string is just constructed for the function call and is destructed again before the rest of the main-function is executed. The segfault happens when you dereference the invalid pointer.
Try the following instead:
const std::string str("bar");
Foo f(str);
This way, the string is still in scope when the data is needed.
Apart from that, the overall approach is not advisable. Better not use void* pointers and raw pointers if possible, or at least manage them safely within an object. Your problem already makes clear why this kind of pointer usage is unsafe and error-prone.
Foo f("bar");
You are passing a reference to a temporary value to the constructor. The lifetime of the object is only inside the constructor. So the void *data points to a deleted memory.
To be more precise, if you are not aware, you may want to know the difference between l-value and r-value in C++.
eg) int a = 5
Here a is l-value and 5 is the r-value. Simply put they are the value category of the data type.
https://en.cppreference.com/w/cpp/language/value_category
You should never store a reference to an r-value. Always examine the life time of the object before performing any operation and ensure the object stay alive till the operation is complete.
Solution
string a = "bar";
Foo foo(a);
Here a is l-value. But it is the user's responsibility to make sure that a's life scope is more than foo.
Or better
string a = "bar";
{
Foo foo(a);
}
This way you ensure that foo is destructed before a
The reason your code crash and burn is because
: Foo(str.c_str())
is calling
Foo(const std::string& str);
and not
Foo(void* newData);
so you have infinite recursion. This is all bad and I advise you to rethink your approach, however just to get it running, cast the str.c_str() to void * explicitly:
: Foo((void *)str.c_str())
And of course make "bar" a stand alone string to avoid dealing with temporaries, and pass the string to constructor. This way the pointer will be valid until the scope with your string ends.
Demo: https://ideone.com/v7YfBX
Firstly I would recommend not using void*
There are very few situations where you need to use void*, and you will loose any useful type information.
If you want to manipulate the bits directly within a std::string object, then from C++ 17, the data method on string gives access to the characters directly, without being constant.
If you want to make your code safer, just store std::string as a member variable of your Foo class, and use the methods available to you.
This will also mean you won't need to manually keep track of the internal pointer of a string passed from c_str or data method calls.
E.g. (partial example)
class Foo {
public:
Foo(const std::string& str);
const char* getData() const;
char* getData();
private:
std::string m_str;
};
Foo::Foo(const std::string& str)
: m_str(str)
{
}
const char* Foo::getData() const
{
return m_str.c_str();
}
char* Foo::getData()
{
// Note: Need C++ 17
return m_str.data();
}
Considering the following class example :
class AClass
{
std::string myString;
public:
...
}
With one of the following accessors :
const std::string& GetMyString() const
{
return myString;
}
versus
const char* GetMyString() const
{
return myString.c_str();
}
Taking into account that myString is initialized once and is never changed, which accessor is better? The first one, or the second one? In what situation one of them is more suitable than its neighbor?
The version returning const std::string& covers a superset of the use cases for returning const char* (after all, it can be converted to the latter by calling .c_str() on the return value), with no added weaknesses. Given that std::string is more flexible in other ways, I'd prefer const std::string& of the two options.
That said, they're both awkward if the owning object in question isn't immortal; even if the string is never changed, if the object itself disappears, the reference to its string is now invalid. If that's a possibility, you might want to either:
Return by value
or
Use a std::shared_ptr<std::string> member and return that (so the lifetime of the string is no longer tied to the lifetime of the object that created it)
I was trying to evaluate how rvalue references effect the design of the class. Say I have an existing class as shown below
class X
{
string internal;
public:
void set_data(const char* s)
{
internal = s;
}
..
..
..
//other stuff
};
This class is used by another module like this:
//another module
{
string configvalue;
X x;
//read configvalue from a file and call set
...
x.set_data(configvalue.c_str());
//use x to do some magic
..
...
}
with rvalue references in place will it be better to provide another member function like so
class X
{
...
...
....
void set_data(string s)
{
internal = std::move(s);
}
};
This will allow the clients of this class to use move semantics and prevent one set of allocate/copy operations per use. This is a highly concocted example but does the same principle apply to all class designs without breaking the 'minimal interface' paradigm.
Anybody insights on this matter are greatly appreciated?
Yes, adding the string overload as you suggest is a good idea. Even without rvalue references such an overload would be a good idea. Otherwise, given a std::string s, to use it would have to:
x.set_data(s.c_str());
whereas
x.set_data(s);
is so much more intuitive (and even slightly more efficient) for the clients of X.
As another option, you could add these two overloads:
void set_data(const string& s) {internal = s;}
void set_data(string&& s) {internal = std::move(s);}
This is roughly equivalent to the single overload you correctly suggested. There is a very slight performance advantage for the two-overload solution. The single-overload solution will cost an extra string move construction when the argument passed is an xvalue (an lvalue that has been cast with std::move). But the move constructor of std::string should be really fast, so this should not be a big deal. I mention it only in the spirit of full disclosure.
If set_data has more than one parameter, the "by-value" approach becomes much more attractive. For example consider the case where you need to pass in two strings. Your choices are:
Solution 1
void set_data(string s1, string s2);
Solution 2
void set_data(const string& s1, const string& s2);
void set_data( string&& s1, const string& s2);
void set_data(const string& s1, string&& s2);
void set_data( string&& s1, string&& s2);
As you can quickly see, Solution 2 scales poorly with the number of parameters.
Finally, in no circumstance should you attempt to apply both solutions to the same type:
Don't do this!
void set_data(string s) {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
void set_data(string&& s) {internal = std::move(s);}
This set of overloads will be ambiguous. Just as in C++03 the following two overloads are ambiguous:
void set_data(string s) {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
Never overload by-value with reference, either lvalue reference nor rvalue reference.
I don't see a reason to have both void set_data(const char* s) and void set_data(string s) as part of the interface. This will create an ambiguity and is prone to side-effects. Moreover, you still pass the argument by value in call to set_data(string s). Instead I would suggest defining the 2 following funcs:
void set_data(const string &s);
void set_data(string &&s);
This way you can have 2 implementations, first will deep copy your string and second one can steal the internals of the string since it's an rvalue (make sure to leave it in a defined state so the destructor will be able to destroy it without problem - for details see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics).
The second version will be invoked automatically either on rvalue string argument or if argument is forced to rvalue, for example by std::move.
If you want to have a by-value option as well you can use the rvalue version of this API combined with string copy constructor: set_data(string(str)).
I decided to see if assigning a reference to a member would make a member a reference. I wrote the following snippet to test it. There's a simple class Wrapper with an std::string as a member variable. I take take a const string& in the constructor and assign it to the public member variable. Later in the main() method I modify the member variable but the string I passed to the constructor remains unchanged, how come? I think in Java the variable would have changed, why not in this code snippet? How exactly do references work in this case?
#include <iostream>
#include <string>
using namespace std;
class Wrapper
{
public:
string str;
Wrapper(const string& newStr)
{
str = newStr;
}
};
int main (int argc, char * const argv[])
{
string str = "hello";
cout << str << endl;
Wrapper wrapper(str);
wrapper.str[0] = 'j'; // should change 'hello' to 'jello'
cout << str << endl;
}
To assign a reference in a constructor you need to have a reference member
class A{
std::string& str;
public:
A(std::string& str_)
: str(str_) {}
};
str is now a reference to the value you passed in. Same applies for const refs
class A{
const std::string& str;
public:
A(const std::string& str_)
: str(str_) {}
};
However don't forget that once a reference has been assigned it can not be changed so if assignment requires a change to str then it will have to be a pointer instead.
Because Wrapper::str is not a reference, it's an independent object. So when you do str = newStr, you're copying the string.
class Wrapper
{
public:
string& str;
Wrapper(string& newStr) : str(newStr) {}
};
Note, you cannot accept a const string& and store it in a string&, you would lose const-correctness in doing so.
You need to use an initializer and declare str as a reference as in:
class Wrapper {
public:
string &str;
Wrapper(string& newStr)
: str(newStr) {
}
};
The way you're writing it, all you are doing is copying the value of the reference you pass to the constuctor. You're not saving the reference. By declaring a reference as a class member and initializing it with a reference to another string instance, you will get the behavior you're looking for.
You should declare Wrapper::str as a string&, not as a string.
Your main body variable is std::string.
Your parameter variable is const std::string&.
The const in references are always "low level const", meaning it modifies the type of object not the actual object.
In contrast a "top level const" modifies an actual object. Read C++ Primer on Top level const for clarification.
Here is how your assignment looks like when you pass arguments:
const std::string& = std::str; //Values are ommited
// i.e const std::string newStr = std::string str
You are initializing a const type reference with a non-const value which is acceptable. You are not supposed to change the value of std::string str using that reference. And, if you try changing the value of newStr inside the constructor, you will get a compilation error.
Next you're doing another assignment inside the constructor which is also acceptable:
std::string = const std::string
The fact that wrap.str[0] didn't change str of main is that, although a reference was used to instantiate class str, class str has its own object and is not linked to main str. Using that reference in a parameter just links that parameter to main str; not main str to class str.
If your class variables were referenced, then it could have changed.