Reputation: 2789
I want to have an object that contains a reference, and put that object into a vector...
Must I use smart pointers instead of a member references in any object I want to push into a vector? This was what I wanted to do:
#include <string>
#include <vector>
using namespace std;
class MyClass {
public:
MyClass(const string& str_ref); //constructor
MyClass(const MyClass& mc); //copy constructor
private:
string& my_str;
};
MyClass::MyClass(const string& str_ref) :
my_str(str_ref)
{}
MyClass::MyClass(const MyClass& mc) :
my_str(mc.my_str)
{}
int main() {
//create obj and pass in reference
string s = "hello";
MyClass my_cls(s);
//put into vector
vector<MyClass> vec;
vec.push_back(my_cls);
return 0;
}
//Throws Error
//ref.cpp:6:7: error: non-static reference member ‘std::string& MyClass::my_str’, can’t use default assignment operator
However it says I need to implement my own operator=() as the default generated one isn't valid but of course, there is no legal way to do so...
#include <string>
#include <vector>
using namespace std;
class MyClass {
public:
MyClass(const string& str_ref); //constructor
MyClass(const MyClass& mc); //copy constructor
MyClass operator=(const MyClass& mc); //operator =
private:
string& my_str;
};
MyClass::MyClass(const string& str_ref) :
my_str(str_ref)
{}
MyClass::MyClass(const MyClass& mc) :
my_str(mc.my_str)
{}
//not a constructor. should not construct new object
//and return that?
MyClass MyClass::operator=(const MyClass& mc) {
if (this != &mc) { //test for self-assignment.
my_str(mc.my_str); //can't reseat refs. this shouldn't work.
}
return *this;
}
int main() {
//create obj and pass in reference
string s = "hello";
MyClass my_cls(s);
//put into vector
vector<MyClass> vec;
vec.push_back(my_cls);
return 0;
}
//THROWS:
//ref2.cpp: In constructor ‘MyClass::MyClass(const string&)’:
//ref2.cpp:18:19: error: invalid initialization of reference of type ‘std::string& {aka //std::basic_string<char>&}’ from expression of type ‘const string {aka const //std::basic_string<char>}’
//ref2.cpp: In member function ‘MyClass MyClass::operator=(const MyClass&)’:
//ref2.cpp:29:18: error: no match for call to ‘(std::string {aka std::basic_string<char>}) //(std::string&)’
So am I forced to use a smart pointer here or anything other than a reference?
EDIT: This is a simplification. String& is not the object being passed, it's a more complex object itself containing a vector object.
Upvotes: 3
Views: 913
Reputation: 23
One caveat. Please be sure to check for self-assignment:
MyClass& MyClass::operator=(MyClass const& from) {
if (this != &from) {
this->~MyClass();
new(this) MyClass(from);
}
return *this;
}
Upvotes: 2
Reputation: 34618
If you want to be able to still use the assignment operator of your member (i.e. std::string& operator=(std::string const&)
) you cannot use the otherwise excellent suggestion of std::reference_wrapper
. But you can rebuild your object from scratch using the copy constructor so your member may actually be a raw reference:
MyClass& MyClass::operator=(MyClass const& from) {
this->~MyClass();
new(this) MyClass(from);
return *this;
}
Upvotes: 1
Reputation: 11667
How about using std::reference_wrapper<T>
? Now you're not forced to refactor your code to allow a smart pointer, but you're also not using an internal pointer that someone may come along later and think they're supposed to delete
.
class MyClass
{
public:
MyClass(string &str_ref)
: my_str(std::ref(str_ref))
{
}
private:
std::reference_wrapper<std::string> my_str;
};
Upvotes: 5
Reputation:
You can store a raw pointer instead of a reference here. Raw pointers can be reseated, and so they're a good way to emulate reseatable references in C++.
class MyClass
{
public:
MyClass(const string& str_ref);
MyClass(const MyClass& mc);
// by the way, operator= should return a reference
MyClass& operator=(const MyClass& mc);
private:
string* my_str;
};
This way, operator=
will be a cinch to implement.
Upvotes: 6