Search code examples
c++constructorpass-by-referencememberostream

Assign reference parameter for ostream to reference member variable


I'm having trouble passing a reference to std::ostream to a class constructor and assigning it to a reference member variable.

I have two files:

// ./include/HelloWorld.hpp
#ifndef __HELLOWORLD_H__
#define __HELLOWORLD_H__

#include <iostream>
#include<string>

class HelloWorld {
    public:
        HelloWorld(std::ostream& MyOut);
        void say();
    private:
        std::ostream &output;
};

#endif
// ./src/HelloWorld.cpp
#include "../include/HelloWorld.hpp"

HelloWorld::HelloWorld(std::ostream &MyOut) : output(MyOut){
    output = MyOut; // Error is thrown here
};

void HelloWorld::say(){
    this->output << "Hello World4!" << '\n';
}

When I run:

g++ -c -fPIC -Wall -Werror -o bin/HelloWorld.o src/HelloWorld.cpp

I get the following error:

src/HelloWorld.cpp: In constructor ‘HelloWorld::HelloWorld(std::ostream&)’:
src/HelloWorld.cpp:5:14: error: use of deleted function ‘std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator=(const std::basic_ostream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’
    5 |     output = MyOut; // Error is thrown here
      |              ^~~~~
In file included from /usr/include/c++/9/iostream:39,
                 from src/../include/HelloWorld.hpp:5,
                 from src/HelloWorld.cpp:2:
/usr/include/c++/9/ostream:405:22: note: declared here
  405 |       basic_ostream& operator=(const basic_ostream&) = delete;
      |                      ^~~~~~~~

Due to this question, I'm assuming I'm not assigning a reference to a reference. But, as far as I understand, I believe both the member variable and constructor parameter are both defined as a reference.

What am I misunderstanding here?

EDIT1: To be clear, I'm not simply asking "How do I make this work?". I'm trying to understand why when I attempt to change where a reference variable points to, there is an attempt to copy an entire object. I thought the whole point (pun intended :P) of reference variables was to avoid copying objects. I fully understand there is a reason for everything and that this does not make sense to me simply due to my ignorance. This question is intended to shore up that ignorance and learn why it works the way it does. The suggested "duplicate" question does not answer this and is 8 years old. Far to old to resurrect.


Solution

  • Here

    HelloWorld::HelloWorld(std::ostream &MyOut) : output(MyOut){   // I
        output = MyOut; // Error is thrown here
    };
    

    You correctly initialize the member reference output from MyOut in the initializer list. I

    You then, II, try to assign MyOut to output, which both are references to the same ostream. If this would compile it would do nothing, because it attempts to assign the same ostream to itself. However, std::ostream cannot be assigned or copied, thats why you get the error.

    The solution is to initialize the member in the member initializer list and not assign it in the constructors body:

    HelloWorld::HelloWorld(std::ostream &MyOut) : output(MyOut) {}