0

I am trying to implement a singleton design pattern without memory allocation. I tried searching for a solution but it seems like every solution was for a singleton defined with memory allocation.

I made the constructor private and the only code I added to the header file to make this a singleton design pattern was:

static ParametersServerPC& ParametersServerPC::GetInstance() {

    static ParametersServerPC instance;
    return instance;

}

This is a derived class from the base class ParametersServerABS which has an empty constructor definition. ParametersServerABS is an abstract class.

When I try to instantiate a ParametersServerPC class in a separate file:

ParametersServerPC& paramServer = ParametersServerPC::GetInstance();

I get this error:

undefined reference to `ParametersServerPC::GetInstance()'

Here are the .cpp and .hpp files:

parameters_server_abs.hpp:

#ifndef PARAMETERS_SERVER_ABS_HPP_
#define PARAMETERS_SERVER_ABS_HPP_

class ParametersServerABS {

    public:

        ParametersServerABS();

        ~ParametersServerABS();

        virtual bool Load() = 0;

};

#endif

parameters_server_abs.cpp:

#include "mid_level/parameters_server_abs.hpp"

ParametersServerABS::ParametersServerABS() {}

ParametersServerABS::~ParametersServerABS() {}

parameters_server_pc.hpp:

#ifndef PARAMETERS_SERVER_PC_HPP_
#define PARAMETERS_SERVER_PC_HPP_

#include <string>

#include "mid_level/parameters_server_abs.hpp"

class ParametersServerPC: public ParametersServerABS {

    public:

        ~ParametersServerPC();

        static ParametersServerPC& GetInstance();

        virtual bool Load();

   private:

        ParametersServerPC(std::string parameterFileName = "parameters.txt");

        std::string _parameterFileName;

};

parameters_server_pc.cpp:

#include "mid_level/parameters_server_pc.hpp"

ParametersServerPC::ParametersServerPC(std::string parameterFileName = "parameters.txt") :
        _parameterFileName(parameterFileName) {

}

ParametersServerPC::~ParametersServerPC() {

}

static ParametersServerPC& ParametersServerPC::GetInstance() {

    static ParametersServerPC instance;
    return instance;

}

virtual bool ParametersServerPC::Load() {

    return true; // TODO

}

my_test_file.cpp

#include "mid_level/parameters_server_pc.hpp"

ParametersServerPC& paramServer = ParametersServerPC::GetInstance();
jlcv
  • 1,688
  • 5
  • 21
  • 50
  • Can you please post all the code of `ParametersServerPC` ? `GetInstance()` looks fine but it doesn't need `static` in definition. – VP. Jan 23 '15 at 14:45
  • `ParametersServerABS` is an abstract class that the `PC` class is derived from. It just has a public constructor and destructor right now. Along with a virtual function that I have not defined yet. The code for the GetInstance() in the `PC` class is in the header file. Right now all it has is a public destructor and private constructor. – jlcv Jan 23 '15 at 14:45
  • @VictorPolevoy Sure one sec. – jlcv Jan 23 '15 at 14:45
  • @JustinLiang just try and put both classes in one single compilable file, together with `main()`, and see what's going on. You may have an inclusion problem or something similar, but from the code above we can just guess – vsoftco Jan 23 '15 at 14:46
  • @VictorPolevoy Sorry for the delay, I thought I fixed it but didn't, I have added the code to my post. Also, I tried removing the `static` specifiers and I get a new error: cannot call member function `'ParametersServerPC& ParametersServerPC::GetInstance()' without object`. @vsoftco I will try this momentarily, thanks! – jlcv Jan 23 '15 at 15:21

3 Answers3

1

It is an acceptable pattern. Here is a MVCE demonstrating the feasability :

#include <iostream>
#include <string>

using namespace std;

class A {
public:
    int ival;
    string strval;

    static A& getInstance();
private:
    A(int ival, string strval): ival(ival), strval(strval) {}
    A(A& src): ival(src.ival), strval(src.strval) {}
    ~A() {};
};

A& A::getInstance() {
    static A instance(1, "foo");

    return instance;
}



int main() {
    A& a = A::getInstance();
    cout << a.ival << endl;

    // A a1 = A::getInstance(); error
    // A a2 = a; error
    // A a3(2, "bar"); error

    return 0;
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Does the destructor have to be private? Maybe that's my problem. – jlcv Jan 23 '15 at 15:40
  • @JustinLiang As the constructors are private, you cannot create another instance outside the class. I wrote the destructor private only to allow any attempt to do `A *pa = A::getInstance(); delete pa;` detected as an error at compile time. Anyway it would be a runtime error since `instance` has not been allocated with `new`. – Serge Ballesta Jan 23 '15 at 15:51
1

First, mark your ~ParametersServerABS(); destructor virtual to be able to delete objects properly. Second, you need to remove virtual and static keywords from parameters_server_pc.cpp file: they are only for definitions (for your header file).

Next, do it right:

class ParametersServerPC {
    // your code

    private:
        ParametersServerPC(std::string parameterFileName = "parameters.txt");
        ParametersServerPC(ParametersServerPC const&) = delete;
        void operator=(ParametersServerPC const&) = delete;
};

Singleton means that you can't get copies of an object: you need to forbid using of copy constructor and copy assignment operator. And anyway I think your problem is in static in your parameters_server_pc.cpp file. Remove it from implementation part (cpp file) in order to fix the problem but LEAVE it in the definition part (header file).

VP.
  • 15,509
  • 17
  • 91
  • 161
  • First question, don't I need to delete `static` keyword from my `parameters_server_pc.hpp` file as well? – jlcv Jan 23 '15 at 15:46
  • No, you need to leave it there but delete it from `parameters_server_pc.cpp`. – VP. Jan 23 '15 at 15:47
  • Thanks for the help! Though I am still getting the error after making all the changes you told me to. Except I did not remove the `static` keyword inside my `GetInstance()` function in the `parameters_server_pc.cpp` file – jlcv Jan 23 '15 at 15:53
1

undefined reference to `ParametersServerPC::GetInstance()'

This seems to be a linker error. If you can post the output of the compilation console we might narrow this down further.

In the meantime you could check your build system and see if you omitted some source files from compilation.

On the singleton pattern there are already some good answers. More on the topic in a description of the pattern and in a general question about singletons.

Community
  • 1
  • 1
ramses728
  • 323
  • 2
  • 12