c++oopoperator-overloadingunassigned-variable

How to implement operator=() for a class that has a reference member variable?


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.


Solution

  • 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.