DLL with STL Woes

Started by
11 comments, last by iMalc 19 years, 3 months ago
Having a little extra time this holiday, i decided to compile my engine as a DLL. This is my first experience with DLLs and it has almost made me give up the idea. Previously the code compiled as a static library with no warnings/errors. From the errors, it appears that i need STL to have a dll-interface before my classes can use STL objects. After some thorough searching, i also came across an article on MSDN stating that while there are workarounds to get STL working, i won't be able to use some containers. Most notably std::list and std::deque. To me it is not worth the effort to spend a whole week and change my code so that it may compile to a dll. And not being able to use STL containers? Im sure there is a workaround, but i have not been able to find a solution yet.
Advertisement
Yeap, that's about it - you simply cannot use some containers with STL in .dlls. I understand your feelings - it took me a while to figure out the whole using STL in .dlls when I converted my engine into a .dll. There is no work around except make your own container classes instead of using theirs. So for you, it would not be worth the effort to make it into a .dll. I hope this helps a bit.

- Drew
You could try another STL implementation, like STLPort (google for it)
I know of STLPort, but can it be used in DLLs?
Would'nt STLPort have the same restrictions as the MSVC implementation?
Sure you can:

#ifndef SPRY_INTERNAL_ALLOCATOR_HPP#define SPRY_INTERNAL_ALLOCATOR_HPP#include <limits>#include <windows.h>namespace Spry{namespace Internal{	template<typename T>	class Allocator	{	public: 		typedef T					value_type;		typedef value_type*			pointer;		typedef const value_type*	const_pointer;		typedef value_type&			reference;		typedef const value_type&	const_reference;		typedef std::size_t			size_type;		typedef std::ptrdiff_t		difference_type;	public : 		template<typename U>		struct rebind		{			typedef Allocator<U> other;		};	public : 		explicit Allocator()		{		}		~Allocator()		{		}		explicit Allocator(Allocator const&)		{		}		template<typename U>		explicit Allocator(Allocator<U> const&)		{		}		pointer address(reference r)		{			return &r;		}		const_pointer address(const_reference r)		{ 			return &r;		}		pointer allocate(size_type cnt, typename std::allocator<void>::const_pointer = 0)		{ 			return reinterpret_cast<pointer>(HeapAlloc(GetProcessHeap(), 0, (cnt * sizeof (T)))); 		}				void deallocate(pointer p, size_type)		{ 			HeapFree(GetProcessHeap(), 0, p); 		}		size_type max_size() const		{ 			return std::numeric_limits<size_type>::max() / sizeof(T);		}		void construct(pointer p, const T& t)		{ 			new(p) T(t); 		}		void destroy(pointer p)		{			p->~T();			p = 0;		//unnecessary in this scope, but silences warnings		}		bool operator==(Allocator const&)		{			return true;		}		bool operator!=(Allocator const& a)		{			return !operator==(a);		}	};}}#endif


Use this class as the allocator for whatever STL container you are using:
std::list<Class*, Spry::Internal::Allocator<Class*> > list;

I don't recommend it, but that doesn't stop most people. :) I think too many people worry about making 'extensible' engines through DLLs rather than just finishing what they have.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Quote:Original post by antareus
I think too many people worry about making 'extensible' engines through DLLs rather than just finishing what they have.


Well I think that is kinda of right - but also you have to consider the fact that using an engine via a .dll is more fun than finishing it [smile]. Seriously though , by getting it into a .dll you can use it (the unfinished engine) a lot easier in test projects compared to copy-pasting code - that is if you have a large library.

As for your tip - what does that exactly do? Use STL in a .dll or let you use STLPort?

- Drew
It uses the heap that is allocated to the process, instead of the private ones used by the module's C runtime library.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
I'm rather confused. Where exactly did you read that you cannot use some of STL in a DLL? What compiler is this to do with?

We use STL extensively at work with .NET and most of our code is in DLLs and we've never had any problem.
Maybe you're trying to use it between the DLL and the EXE? Perhaps each STL container should be entirely contained within the DLL or the EXE. i.e. use accessor functions instead of passing the list between DLL & EXE.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Quote:Original post by iMalc
I'm rather confused. Where exactly did you read that you cannot use some of STL in a DLL? What compiler is this to do with?

We use STL extensively at work with .NET and most of our code is in DLLs and we've never had any problem.
Maybe you're trying to use it between the DLL and the EXE? Perhaps each STL container should be entirely contained within the DLL or the EXE. i.e. use accessor functions instead of passing the list between DLL & EXE.


Quote:
Note that you may not export a generalized template. The template must be instantiated; that is, all of the template parameters must be supplied and must be completely defined types at the point of instantiation. For instance "stack<int>;" instantiates the STL stack class. The instantiation forces all members of class stack<int> to be generated.

Also note that some STL containers (map, set, queue, list, deque) cannot be exported. Please refer to the More Information section to follow for a detailed explanation.


MSDN. You have to use IE to view the page - it will not work correctly in FireFox.

- Drew
Quote:
Note that you may not export a generalized template. The template must be instantiated; that is, all of the template parameters must be supplied and must be completely defined types at the point of instantiation. For instance "stack<int>;" instantiates the STL stack class. The instantiation forces all members of class stack<int> to be generated.

Also note that some STL containers (map, set, queue, list, deque) cannot be exported. Please refer to the More Information section to follow for a detailed explanation.

This is true, but it doesn't mean you can't use the STL containers. The same code will be generated in both the DLL and EXE for the container, so reading from a list in an EXE that was created in a DLL isn't a problem. Problems occur when you modify the list (adding/removing nodes, changing the value of a node is OK) as this could result in allocating or releasing memory on different heaps (the EXE's and the DLL's)....things start to go *splat*.

antareus's solution prevents this from happening. The allocator object explicitly allocates & releases memory on the EXE's heap, so even if the allocator is called (by the container) from within the DLL the container will always be using the EXE's heap for allocating & releasing memory.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V

This topic is closed to new replies.

Advertisement