-1

I am trying to add to my class the output operator << but in compiling (VS2013) I have a message:

"error C2280:
'std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const
std::basic_ostream<char,std::char_traits<char>> &)' : attempting to
reference a deleted function".

here is my code:

#include "Client.h"

Client::Client(MyString id, MyString full_name, char gender, unsigned short age, unsigned short hobbies_num, char** hobbies_list)
{
    this->id = id;
    this->full_name = full_name;
    if (gender == 'm' || gender == 'M')
        this->gender = 'M';
    else if (gender == 'f' || gender == 'F')
        this->gender = 'F';
    else
        cout << "wrong gender value" << endl;
    if (age >= 18)
        this->age = age;
    else
        cout << "wrong age value" << endl;
    this->hobbies_num = hobbies_num;
    this->hobbies_list = hobbies_list;
}

Client::Client(const Client& other)
{
    this->id = other.id;
    this->full_name = other.full_name;
    this->gender = other.gender;
    this->age = other.age;
    this->hobbies_num = other.hobbies_num;
    this->hobbies_list = other.hobbies_list;
}

Client::~Client()
{
    for (int i = 0; i < hobbies_num; i++) // deleting 2 dimension array
        delete[] hobbies_list[i];
    delete[] hobbies_list;
}

Client& Client::operator = (const Client& other)
{
    if (this->id == other.id) //checks if the client is not the same client
        return *this;
    else
    {
        for (int i = 0; i < hobbies_num; i++) // deleting 2 dimension array
            delete[] hobbies_list[i];
        delete[] hobbies_list;
        return Client(other);
    }

}

ostream& operator << (ostream& cout, const Client& for_print)
{
    return cout << for_print.id << endl 
                << for_print.full_name << endl 
                << for_print.gender << endl 
                << for_print.age << endl 
                << for_print.hobbies_num << endl;
}

The message is on the line stating at return cout. here are the prototypes:

#include "MyString.h"
#include <iostream>
#include <stdlib.h>

using namespace std;
class Client
{
    MyString id;
    MyString full_name;
    char gender;
    unsigned short age;
    unsigned short hobbies_num;
    char ** hobbies_list;
public:
    Client(MyString, MyString, char, unsigned short, unsigned short, char**);
    Client(const Client& other);
    ~Client(); //dtor
    Client& operator = (const Client&);  //=
    friend ostream& operator << (ostream&, const Client& for_print);
};

I didn't find any solution online. The same command works for me in another class at the same solution.

RD7
  • 628
  • 4
  • 9
  • 20
  • 5
    Usually this error means you're trying to copy an `ostream` somewhere. It would be easier to help if you could post a minimal but self-contained code sample that reproduces the problem. – juanchopanza Aug 22 '14 at 05:24
  • You could mark the line the error's associated with (which I suspect isn't even listed at present).... – Tony Delroy Aug 22 '14 at 05:29
  • 4
    Also, don't call your function parameter `cout`.... – T.C. Aug 22 '14 at 05:30
  • [This may help](http://stackoverflow.com/questions/6010864/why-copying-stringstream-is-not-allowed) but I'm not sure it's really a dupe without seeing the code that causes the problem. – Retired Ninja Aug 22 '14 at 05:36
  • Please, don't deallocate memory in a destructor you have allocated elsewhere. If you initialize your object with statically allocated strings (or global or local variables) you'll end trying to delete global or stack allocated variables. – Luis Colorado Aug 22 '14 at 05:48
  • @Luis Huh? `char**` is absolutely the wrong way to go about implementing an array of strings, but as implemented, his class takes ownership of the allocated memory in the constructor. Where other than the destructor would he delete this memory? – Praetorian Aug 22 '14 at 06:18
  • @Praetorian: char ** effectively is not the best way to use an array of strings (better when you have a string type) but it can be done (it's the way the question was asked) What I mean is that if you are going to delete things in a destructor, you have to assure that no external references remain after that, or you'll have to invalidate all of them also. And of course you can't do it in the answer I publish below this comment. – Luis Colorado Aug 22 '14 at 08:15

1 Answers1

0

You don't post the exact place of the compiler error, but I'll try to guess it. Suppose you try to do the following in your code (I won't try to use any C++11 construct to be portable):

char *hobbies[] = {
    "hobbie1",
    "hobbie2",
    /* ... */
};
...

Client a("cl1", "joseph", 'm', 20, hobbies, sizeof hobbies/sizeof hobbies[0]); 
/* object declaration with initialization, constructor is called for a */

and then

a = Client("cl2", "john", 'm', 22, hobbies, sizeof hobbies/sizeof hobbies[0]); 
/* assignment statemement, constructor is being called for right expression 
 * and then assignment operator is called to assign it to a.  
 * Equivalent to:
 * a.Client::operator=(Client("cl2",...));
 * a new object is created by the compiler, passed as parameter and destroyed
 * when the call to operator= is finished, before assigning to a. 
 */

In this last statement, the compiler tries to construct a new object (for the expression evaluation) and assign it to a, using operator Client::operator=(const Client&other); with parameter other instantiated to this new created object (the compiler just deallocates it, calling the destructor, when the statement finishes, you can check this putting tracing code in the ~Client() body). Just when you return the value Client(other) (in the final return statement of the Client::operator= body), you instantiate a new expression of type Client with values copied with something that will be deleted by the compiler when the expression evaluation finishes (either the client created to pass it to the assignment operator or the one you construct for the return statement) They cease to exist when the return statement is just executed, so you cannot access them outside the operator call (I think this is the error you get from the compiler). You had better to rewrite the Client::operator=(const Client& other) this way:

Client& Client::operator=(const Client& other)
{
    if (this == &other)  /* the same object in both sides */
        return *this;
    else {
        /* delete local memory assignated 
         * **in constructor** to object, not elsewhere
         */
        /* do the actual assignments onto *this, 
         * don't create another instance or value.  This
         * is an assignment operation, you are supposed to
         * change the values of *this
         */

        return *this;  
        /* **never** return a local copy made by the compiler
         * inside the function call, it ceases to exist just
         * on returning from it */
    } /* if */
} /* Client::operator=(const Client&) */

I don't believe this same example compiles ok in another environment, it's wrong C++ construct.

You can also see how I have called the constructor with static char arrays (not strings) so they must not be deallocated in the destructor of Client (to illustrate that you might better not deallocate memory in the destructor if it has been allocated elsewhere).

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31