jlcv
jlcv

Reputation: 1808

C++ Singleton: `Undefined reference to` error

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();

Upvotes: 0

Views: 2708

Answers (3)

ramses728
ramses728

Reputation: 343

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.

Upvotes: 1

VP.
VP.

Reputation: 16765

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

Upvotes: 1

Serge Ballesta
Serge Ballesta

Reputation: 149175

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;
}

Upvotes: 1

Related Questions