Jump to content

  • Log In with Google      Sign In   
  • Create Account

Dealing with "needs to have dll-interface to be used by clients of class"


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
13 replies to this topic

#1 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 09:55 AM

I like warning free code, especially for a dll, these warnings are the only left right now I have to deal with. I am not sure how to deal with them however. If someone could point me in the right direction that would be great.

 

std::basic_string<_Elem,_Traits,_Ax>
std::map<_Kty,_Ty>
std::vector<_Ty>
std::list<_Ty>'
std::_List_iterator<_Mylist>

 

Update:

 

So to compound this, I get this error when setting up my .exe project:

 

 

Error 49 error C2491: 'ParticlesEngine::Singleton<T>::instance' : definition of dllimport static data member not allowed

 

The Code:

 

#ifndef _SINGLETON_H
#define _SINGLETON_H

#define NULL 0


#ifdef PARTICLESENGINE_DLL 
#define PARTICLESENGINE_API __declspec( dllexport )
#else
#define PARTICLESENGINE_API __declspec( dllimport )
#endif

namespace ParticlesEngine
{

	template <typename T>
	class PARTICLESENGINE_API Singleton
	{
	public:
		Singleton<T>(void)
		{    
		}
 
		static inline T* getInstance(void) 
		{ 
			if(instance == NULL) 
			{
				instance = new T();
			}
			return instance;
		} 

		static inline bool exists( void ) { return instance != 0; }
   
		virtual ~Singleton( void ) { instance = 0; }

	protected:
		static T* instance;
	};

	template <typename T>
	T* Singleton<T>::instance = 0;

}

#endif

 

 

 

Edited by harshman_chris, 17 January 2013 - 10:25 AM.


Sponsor:

#2 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
1Likes
Like

Posted 17 January 2013 - 10:51 AM

Warning C4251. You have a DLL interface that depends on code that is compiled externally, is statically linked into the DLL & EXE, and as a result you may have a version mis-match between the data structure used in the DLL, vs the 'same' (but possibly not) data structure used in the exe.

 

In a nutshell, if your DLL links to the release CRT, and then returns a std::string. That string will be allocated in the DLL, and may end up being freed/reallocated in the EXE. Even worse, the data sizes of the STL containers may change size (i.e. iterator debugging info), which can cause all manner of buffer overruns and other niceties.

 

To avoid this warning, you have two choices:

 

a) Don't use STL,

b) Don't use STL.

 

There is a third option, which is to simply ignore the warning. The warning is only a problem when trying to link a debug build DLL with a release build app (or visa-versa). If both EXE & DSO are linking to the same CRT, then there is no problem.

As for you other problem, stop putting the class implementations as non-inlined parts of a header file. This won't work with DLLs. The second you attempt to link to the DSO, the static variable is declared as a new global variable in the executable, and it's declared as being "dllimport", which is WRONG. It needs to be declared once in your DLL as "dllexport". Source files are there for a reason! Use them more! :P



#3 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 10:54 AM

Alright I kinda though that, I will go edit my headers to correct that issue.

 

About stl, I can switch to char instead of string for most of it, it will take a bunch of work, but how can I replace vector and map and list which I use alot without having to write my own.

 

Thanks



#4 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
1Likes
Like

Posted 17 January 2013 - 10:57 AM

[Actually there is another way to avoid the STL problem.....  Don't expose in in the DSO interface]

 

class Foo
{
public:
  EXPORT Foo();
  EXPORT Foo(const Foo&);
  EXPORT ~Foo();
 
  EXPORT const char* name() const;
  EXPORT void setName(const char* n);
private:
  std::string m_name;
};

 

And just to keep the pedants at bay, you can finalise the class if you really want to avoid the problem of 'Foo' being of an unknown size (although disabling SECURE_CSL and building the DSO in release normally avoids all but the most extreme edge cases).

 

class Foo
{
  Foo(const Foo&);
public:
  EXPORT static Foo* create();
  EXPORT ~Foo();
 
  EXPORT const char* name() const;
  EXPORT void setName(const char* n);
private:
  std::string m_name;
};



#5 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
1Likes
Like

Posted 17 January 2013 - 11:04 AM

Alright I kinda though that, I will go edit my headers to correct that issue.

 

About stl, I can switch to char instead of string for most of it, it will take a bunch of work, but how can I replace vector and map and list which I use alot without having to write my own.

 

Thanks

 

 

Stop exporting the entire f***ing class! Exporting the entire class is really bad practice. It will attempt to export ALL of your member variables, private functions, inline functions, etc. Just export the public functions you need, and be done with it (but remember to always export the ctor, copy ctor, dtor; and also make sure that your ctor is virtual if you intend to use it as a base class. This isn't 'good practice', it's required).

 

You can pass simpler forms of container across the boundary provided their layout and size remain constant. Pass this class by value across the DLL boundary, AND DO NOT EXPORT IT!!  (It's inline for a reason!)

 

template< typename T >
class ConstVector
{
public:
    inline ConstVector( const std::vector<T>& data )
        : m_begin(0), m_end(0)
    {
        if(data.size())
        {
            m_begin = &data[0];
            m_end = m_begin + data.size();
        }
    }
    inline ConstVector( const ConstVector<T>& data )
        : m_begin(0), m_end(0)
    {
    }
    inline ~ConstVector()
    {
    }
    inline size_t size() const
    {
        return m_end - m_begin;
    }
    inline const T* begin() const
    {
        return m_begin;
    }
    inline const T* end() const
    {
        return m_end;
    }
    inline operator std::vector<T> () const
    {
        return m_begin ? std::vector<T>(m_begin, m_end) : std::vector<T>();
    }
private:
    const T* m_begin;
    const T* m_end;
};

 

(I've not actually tested that code, but it should be about right..... )



#6 frob   Moderators   -  Reputation: 21285

Like
2Likes
Like

Posted 17 January 2013 - 11:12 AM

Stop exporting the entire f***ing class! Exporting the entire class is really bad practice. It will attempt to export ALL of your member variables, private functions, inline functions, etc. Just export the public functions you need, and be done with it

 

Specify your interface to the library.  This is true any time you cross a boundary (such as a dll or even a networking protocol).

 

a) Don't use STL,
b) Don't use STL.

Icky.

 

Use the standard library.  Use it and embrace it.  The library is incredibly useful.

 

DLLs have a very clear type of interface.  That interface passes buffers of data, not c++ objects.  

 

It isn't that much different than any other boundary, such as a network boundary or file system boundary; you don't just dump the entire class but instead serialize the data into a boundary-crossing interface.


Check out my personal indie blog at bryanwagstaff.com.

#7 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
2Likes
Like

Posted 17 January 2013 - 12:14 PM

a) Don't use STL,
b) Don't use STL.

 

Icky.

 

Use the standard library.  Use it and embrace it.  The library is incredibly useful.


15 years ago I had that opinion, but after a far too many years maintaining the plug-in architectures for a number of 3D apps, I've developed a lot of contempt for the design of STL allocators & containers (the algorithms are fine, if a little inefficient in places). Yes you can approach everything with a serialise/deserialise mindset, but it just leads to performance hot spots in my experience (or more accurately, it just makes everything a little bit warm all over). If at some point down the line you need to resolve the performance issues, it becomes a real PITA. For any DSO heavy application, it's going to be far easier to simply restrict yoruself to using your own containers (which are of a known size & implementation that you can easily pass across the boundary directly). STL just gets in the way of that imho. I've yet to see a single DLL whose quality is improved by the presence of STL.....  Most of the time, it simply encourages junior developers to make silly mistakes in the API (for example, forgetting that returning const reference to a std::vector is bad news).  My 2 cents.



#8 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 12:21 PM

Alright there is a lot of information above I am working on understanding, thank you all for your help so far.

 

So to not export the entire class I need to add "EXPORT" in front of everything I want to export in the header files. However I shouldn't add EXPORT to functions that are Inline? In addition I should change all my functions that take std::string as a parameter to char, and then keep the std::string's internal or get rid of them all together.

 

 

To the other issue with static data members, I moved the Singleton<T>::instance to the c++ file, now I get Linker errors for each class which is a singleton, which then causes more issues.

 

I am not sure how to solve this:

 

My Singleton c++ just to make sure I did make any errors.

 

#include "Singleton.h"

using namespace ParticlesEngine;

template <typename T>
T* Singleton<T>::instance = 0;

Edited by harshman_chris, 17 January 2013 - 12:23 PM.


#9 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
1Likes
Like

Posted 17 January 2013 - 12:35 PM

You need to export EACH specialisation to the DLL. You cannot export a template to a DLL.

 

template class DLL_EXPORT Singleton<FooType1>;



#10 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 12:45 PM

You need to export EACH specialisation to the DLL. You cannot export a template to a DLL.

 

template class DLL_EXPORT Singleton<FooType1>;

 

 

Something like this, but this doesn't work.

#include "Singleton.h"

#include "GameInfo.h"
#include "Logger.h"
#include "SoundManager.h"
#include "SceneManager.h"
#include "ResourceManager.h"

using namespace ParticlesEngine;

template class DLL_EXPORT GameInfo* Singleton<GameInfo>::instance = 0;
template class DLL_EXPORT Logger* Singleton<Logger>::instance = 0;
template class DLL_EXPORT SoundManager* Singleton<SoundManager>::instance = 0;
template class DLL_EXPORT SceneManager* Singleton<SceneManager>::instance = 0;
template class DLL_EXPORT ResourceManager* Singleton<ResourceManager>::instance = 0;


#11 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
1Likes
Like

Posted 17 January 2013 - 01:14 PM

Originally you were exporting the entire singleton class no? That kinda implies you are trying to do this:

 

// Implementation MUST be in the cpp file (otherwise it gets redefined in the header file in multiple compilation units)
template<typename T>
T* Singleton<T>::instance = 0;

// and now we export the class specialisations.
template class DLL_EXPORT Singleton<GameInfo>;
template class DLL_EXPORT Singleton<Logger>;
template class DLL_EXPORT Singleton<SoundManager>;
template class DLL_EXPORT Singleton<SceneManager>;
template class DLL_EXPORT Singleton<ResourceManager>;

 

If you just want to export the variable only, leaving the rest inline, then :

 

template DLL_EXPORT GameInfo* Singleton<GameInfo>::instance = 0;
template DLL_EXPORT Logger* Singleton<Logger>::instance = 0;
template DLL_EXPORT SoundManager* Singleton<SoundManager>::instance = 0;
template DLL_EXPORT SceneManager* Singleton<SceneManager>::instance = 0;
template DLL_EXPORT ResourceManager* Singleton<ResourceManager>::instance = 0;



#12 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 01:30 PM

A couple of things, I need to replace DLL_EXPORT with PARTICLESENGINE_API from this:

#ifdef PARTICLESENGINE_DLL 
#define PARTICLESENGINE_API __declspec( dllexport )
#else
#define PARTICLESENGINE_API __declspec( dllimport )
#endif

 

 

Also there is this error now:

 

 

Error 33 error C2143: syntax error : missing ';' before '=' c:\users\100312531\desktop\project-seventeen\particleengineproject\particlesengine\singleton.cpp 12 1 ParticlesEngine

 

that happens on each of those variable declaration lines

 


#13 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
0Likes
Like

Posted 17 January 2013 - 01:33 PM

Ahh yup, you might have wanted this instead. My bad!

 

 
// Implementation MUST be in the cpp file (otherwise it gets redefined in the header file in multiple compilation units)
template<typename T>
T* Singleton<T>::instance = 0;
template PARTICLESENGINE_API GameInfo* Singleton<GameInfo>::instance;
template PARTICLESENGINE_API Logger* Singleton<Logger>::instance;
template PARTICLESENGINE_API SoundManager* Singleton<SoundManager>::instance;
template PARTICLESENGINE_API SceneManager* Singleton<SceneManager>::instance;
template PARTICLESENGINE_API ResourceManager* Singleton<ResourceManager>::instance;



#14 harshman_chris   Members   -  Reputation: 184

Like
0Likes
Like

Posted 17 January 2013 - 02:30 PM

No Worries, thank you for all your help.

 

There is one more issue left which is similar but different enough to warrant another post, rather than continue this one.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS