3

I have an a class which is singleton as defined follows

class myData {
private:
    myData (void); // singleton class.
    // Copy and assignment is prohibted.
    myData (const myData &);
    myData & operator=(const myData &);
    static myData* s_pInstance;

public:
    ~myData (void);
    static const myData & Instance();
        static void Terminate();

    void myFunc() { cout << "my function..." ;}
};

// In cpp file.

myData* myData::s_pInstance(NULL);

myData::myData(){}

myData::~myData()
{
    s_pInstance = NULL;
}

const myData& myData::Instance()
{
    if (s_pInstance == NULL)
    {
        s_pInstance = new myData();
    }

    return *(s_pInstance); // want to avoid pointer as user may deallocate it, so i used const referense
}

void main() {

    (myData::Instance()).myFunc();

}

I am getting following error

error C2662: 'myData::myFunc' : cannot convert 'this' pointer from 'const myData' to 'myData&'

how to avoid above problem and call a function from Instance function which is returning const reference?

Thanks!

Gabe
  • 84,912
  • 12
  • 139
  • 238
venkysmarty
  • 11,099
  • 25
  • 101
  • 184

4 Answers4

8

You'd want to declare func() as a constant member function, so the compiler knows it won't violate the const'd return value from the instance() function.

You could instead also make the instance() function return a 'regular' reference as apposed to a const one.

So either turn: void myFunc() into void myFunc() const

Or turn: const myData& myData::Instance() into myData& myData::Instance()

Seb Holzapfel
  • 3,793
  • 1
  • 19
  • 22
4

If you are calling a function on a const reference, the function you call must also be const, in your case void myFunc() const.

Otherwise you might return a non-const reference, if that works better.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
3

The error says that myData::Instance() is a const instance of the class, and it can't call myFunc() on that, because myFunc() might change the instance, and you can't change a const instance.

Of course, you know that myFunc() can't really change the instance, but you must advertise this fact, as follows:

void myFunc() const { cout << "my function..." ;}

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
3

Avoiding the whole discussion of whether Singleton is a good to have pattern or the source of all evil, if you are actually implementing a singleton, chances are that const correctness will not work there as you expect it, so you should be aware of some pitfalls.

First your error: your Instance() static member returns a const reference, and that means that you can only perform operations that do not modify the object, i.e. call member functions marked as const, or use public members if present in a way that do not modify their values. My suggested solution is modify Instance() to return a non-const reference, rather than making func() const as others suggest.


Now for a longer explanation to the problem of const-correctness in general when applied to your particular Singleton problem. The basic problem is that when you implement a type, you divide those members that modify the object from those that don't, and you mark the latter as const member functions so that the compiler knows of your promise (allows you to call that method on a constant object) and helps you not break it (complains if you try to modify the state in the definition of the method). A method that is marked as const can be applied to both a constant and non constant object, but a method that is not marked const can only be applied to an object that is not const.

Back to the original piece of code, if you implement a singleton and the only way of accessing the object is by an Instance() method that returns a const reference, you are basically limiting all user code to use only const methods implemented in your interface. That means that effectively either all methods are non-mutating, or they are useless (const_cast should never be used). That in turn means that if you have any non-const operation you want to provide an Instance() method that returns a non-const reference.

You could consider implementing two variants of Instance(), but that will not be really helpful. Overload resolution will not help in user code to determine which version to use, so you will end up having to different methods: Instance(), ConstInstance() (choose your names), which means that it is up to user code to determine which one to use. The small advantage is that in their code, the choice of accessor will help documenting their intended usage, and maybe even catch some errors, but more often than not they will just call the non-const version because it works.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489