LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-16-2006, 02:38 PM   #1
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092
Blog Entries: 1

Rep: Reputation: 90
Question c++: Problems with a singleton (as a so)


I'm trying to create a singleton class. I think I have been able to code it correctly after spending sometime learning a thing or two I don't know very well about C++.

Anyway.... I have put this class in a so. But when I start the application that uses this library, it complais because it can't find one symbol (one the class' static members).

header file (I'm using QT):
Code:
#include <QSqlDatabase>

#ifndef SMILE_H_
#define SMILE_H_

#endif /*SMILE_H_*/

class SmileDB {
	
private:
	static SmileDB *instance;

public:
	static SmileDB *getInstance();
	
	void setDatabase(QSqlDatabase *database);

private:
	QSqlDatabase *database;
};
Here's the implementation:
Code:
#include <QSqlDatabase>
#include "smiledb.h"

SmileDB * SmileDB::getInstance() {
	if (! SmileDB::instance) {
		SmileDB::instance = new SmileDB();
	}
	
	return SmileDB::instance;
}

void SmileDB::setDatabase(QSqlDatabase *database) {
	if (! this->database) {
		this->database = database;
	}
}
When I start the application, I get this:
Code:
symbol lookup error: lib/libsmiledb.so.1: undefined symbol: _ZN7SmileDB8instanceE
Any ideas what I'm missing?

Last edited by eantoranz; 02-16-2006 at 02:39 PM.
 
Old 02-16-2006, 05:08 PM   #2
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
In the implementation you need to initialise the static as follows:

SmileDB * SmileDB::instance = 0;

You also want the constructor to be private.
 
Old 02-16-2006, 05:34 PM   #3
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Quote:
Originally Posted by graemef
In the implementation you need to initialise the static as follows:

SmileDB * SmileDB::instance = 0;
...
or you could use a lazy singleton
Code:
class SmileDB 
{
public:
    static SmileDB *getInstance()
    {
        static SmileDb* instance = 0;
        if(!instance)instance = new SmileDB();
        return instance;
    }
.......
although i much prefer returning a refernce instead of a pointer, but this depends of the lifetime of the singleton. I use a template class for singletons which have the life time of the app and register an atexit func to delete the instance; where getinstance returns a ref.
also you may want to include a few funcs in private so that they are not auto created.
Code:
SmileDB(const SmileDB&){;}
SmileDB& operator=(const SmileDB&){;}
 
Old 02-17-2006, 09:54 AM   #4
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90


Can't get it to work as a so. I'll try the static way to see how it goes.
 
Old 02-17-2006, 12:44 PM   #5
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
I get exactly the same error... only that in compiletime, instead of runtime.

Code:
smiledb.o: In function `SmileDB::getInstance()':
smiledb.cpp:(.text+0x29): undefined reference to `SmileDB::instance'
smiledb.cpp:(.text+0x5a): undefined reference to `SmileDB::instance'
I think it's a problem in my code. Can you show me one very simple example of a singleton (c++) so that I can extend from it? both the .h and the .cpp

With just a getInstance() will be enough.. and thanks for your help so far.
 
Old 02-17-2006, 01:05 PM   #6
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
this is a very basic version.
Code:
class Singleton
{
	public:
	static Singleton& manager( void )
	{
		static Singleton* instance =0;
		if(!instance)instance = new Singleton();
		return *instance;
	}
	void foo( void){;}
	private:
	Singleton(){;}
	~Singleton(){;}
};
foo would be called like so:
Code:
Singleton::manager().foo();

Last edited by dmail; 02-17-2006 at 01:07 PM.
 
Old 02-17-2006, 01:50 PM   #7
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
Quote:
Originally Posted by graemef
In the implementation you need to initialise the static as follows:

SmileDB * SmileDB::instance = 0;

You also want the constructor to be private.
As graemef had said, I had to write that beautiful line... but I hadn't realized it was a static part.... so it's out of any method scope:

Code:
#include "smiledb.h"

SmileDB * SmileDB::instance = 0;

SmileDB::SmileDB() {}
Now... about the dmail's way... I read somewhere that this way is better, cause it avoids memory leaks.. could you elaborate on this, please? (I'm going to give it a try right away.... the marvels of using a CVS )
 
Old 02-17-2006, 02:39 PM   #8
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
How do you like it? ;-)

.h
Code:
#include <QSqlDatabase>

#ifndef SMILE_H_
#define SMILE_H_

#endif /*SMILE_H_*/

/**
 * Clase SmileDB que es la conexion a la DB de smile
 * 
 */
class SmileDB {
	
private:
	SmileDB();
#ifdef LAZY
private:
#else
public:
#endif
	~SmileDB();
	
#ifndef LAZY
private:
	static SmileDB * instance;
#endif

public:
	/**
	 * Retornar la instancia de SmileDB
	 */
#ifdef LAZY
	 static SmileDB & getInstance();
#else
	 static SmileDB * getInstance();
#endif
	
	/**
	 * Guardar la conexion a DB (si no ha sido definida previamente)
	 */
	void setDatabase(QSqlDatabase *database);
	
private:
	QSqlDatabase *database;
};
.cpp
Code:
#include <QSqlDatabase>
#include "smiledb.h"

#ifndef LAZY
SmileDB * SmileDB::instance = 0;
#endif

SmileDB::SmileDB() {}
SmileDB::~SmileDB() {
#ifndef LAZY
	delete SmileDB::instance;
#endif
}

#ifdef LAZY
SmileDB & SmileDB::getInstance() {
	static SmileDB* instance;
	if (! instance) {
		instance = new SmileDB();
	}
	return *instance;
}
#else
SmileDB * SmileDB::getInstance() {
	if (! SmileDB::instance) {
		SmileDB::instance = new SmileDB();
	}
	return SmileDB::instance;
}
#endif

void SmileDB::setDatabase(QSqlDatabase *database) {
	if (! this->database) {
		this->database = database;
	}
}
 
Old 02-19-2006, 02:43 PM   #9
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
Both implementations work (thank you very much).

Now I have a little trickier problem. How can you make a singleton that can be extended? Say, you have a number of classes that you want to make singletons, so you have a single instance of each one of them. I don't want to have to write the same code over and over again in each one. Is there an easy way to accomplish it?
 
Old 02-19-2006, 03:09 PM   #10
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
For a single thread, you can use this template
Code:
#ifndef _SINGLETON_H_
#	define _SINGLETON_H_

namespace pattern
{
template< class T >
class Singleton
{
public:

	inline static T& manager(void)//getter for the singleton
	{
		if( ! m_instance )//check
		{	//create the instance of the derived class
			m_instance = new T();
			//register the function to be called at exit
			atexit( Pattern::Singleton<T>::destroy );	
		}
		return (*m_instance);//return the reference
	}
protected:
	//called when the app exits
	static void destroy(void)
	{ 
		if(m_instance){ delete m_instance; m_instance = 0; } 
	}
	Singleton(void){;}//constructor
	~Singleton(void){;}//destructor
private:
	static T* volatile m_instance;//the instance of the 

	//declare two other functions so the compiler doesn't auto create
	//them, these are in private so that there is no way of calling them
	Singleton(const Singleton&){;}
	Singleton& operator=(const Singleton&){;}
};

};//namespace pattern

//intailise the static
template<class T>T* volatile Pattern::Singleton<T>::m_instance = 0;
#endif //_SINGLETON_H_
and to inherit from this use something like
Code:
class Singleton_timer : public Pattern::Singleton<Singleton_timer>
{ 
public:
//public func here

private:
	friend class Pattern::Singleton<Singleton_timer>;
	Singleton_timer( void ){;}
	~Singleton_timer( void ){;}
};

//typedef a smaller name for this class
typedef Pattern::Singleton<Singleton_timer> Timer;
Therefore a singleton timer would be called like so:
Code:
Timer::manager().func_to_call_here();

Last edited by dmail; 02-19-2006 at 03:18 PM.
 
Old 02-20-2006, 09:11 AM   #11
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
It works... but I have a problem. I have to set the contructor of the extending class as public, because if I set it to private, it wont compile:

Code:
../comun/formas/login/../../smiledb/../singleton.h: In static member function 'static T& Smile::Singleton<T>::getInstance() [with T = Smile::SmileDB]':
../comun/formas/login/login.cpp:27:   instantiated from here
../comun/formas/login/../../smiledb/smiledb.h:16: error: 'Smile::SmileDB::SmileDB()' is private
../comun/formas/login/../../smiledb/../singleton.h:40: error: within this context
 
Old 02-20-2006, 09:38 AM   #12
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Really?
Did you include this line in the inherited class?
Code:
	friend class Pattern::Singleton<CLASS_NAME_HERE>;
If you did can I see your code please, because this does and should work. ;( It gives the singleton access to private in the inherited class.

Last edited by dmail; 02-20-2006 at 09:41 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Marvell Yukon Network driver problems, Lilo Windows boot Problems mellowdog Slackware - Installation 7 01-25-2006 02:18 AM
Triple check singleton pattern dmail Programming 0 12-19-2005 08:56 AM
singleton pattern in C++? Thinking Programming 7 11-13-2005 07:45 PM
Problems, problems, problems. Lets start with the soundcard Kre8ive Linux - Newbie 5 08-07-2003 01:20 AM
Problems, problems, problems. Lets start with the ES 1868 AudioDrive Kre8ive Linux - Newbie 1 08-06-2003 07:04 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:57 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration