I have the following code:
In DLL1:
in .h file:
class MyClass
{
public:
MyClass();
private:
std::string m_name;
};
class __declspec(dllexport) Foo
{
private:
struct Impl;
Impl *pimpl;
public:
Foo();
virtual ~Foo();
};
struct Foo::Impl
{
std::vector<MyClass> m_vec;
std::vector<MyClass> &GetVector() { return m_vec; };
};
in .cpp file:
Foo::Foo() : pimpl ( new Impl )
{
}
Foo::~Foo()
{
delete pimpl;
pimpl = NULL;
}
[EDIT]
In DLL2
in .h
class Bar : public Foo
{
public:
Bar();
virtual ~Bar();
};
in .cpp:
Bar::Bar()
{
}
Bar::~Bar()
{
}
In DLL3:
extern "C" __declspec(dllexport) Foo *MyFunc(Foo *param)
{
if( !param )
param = new Bar();
return param;
}
In main application:
void Abc::my_func()
{
Foo *var = NULL;
// loading the DLL3 and getting the address of the function MyFunc
var = func( var );
delete var;
}
Now, I presume that the copy constructor should be private as it does not make sense to copy both Foo and Bar objects.
Now the question I have is: should Bar also have copy constructor and assignment operator? [/EDIT]
Notice that MyClass is not exported and does not have a destructor.
Is this generally how you write the code?
The problem is that I have a crash on Windows (8.1 + MSVC 2010, if it matters). I can post more code if needed, but for now just want to make sure I don't do something obviously wrong.
The crash happens after I step out of the Base destructor and the stack trace says:
ntdll.dll!770873a6() [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] ntdll.dll!7704164f()
ntdll.dll!77010f01() KernelBase.dll!754a2844()
dll1.dll!_CrtIsValidHeapPointer(const void * pUserData) Line 2036 C++ dll1.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1322 + 0x9 bytes C++ dll1.dll!_free_dbg(void * pUserData, int nBlockUse) Line 1265 + 0xd bytes C++ dll1.dll!operator delete(void * pUserData) Line 54 + 0x10 bytes C++ dll1.dll!Foo::`vector deleting destructor'() + 0x65 bytes C++
Thank you.
UPDATE:
Even if I put following code in the
extern "C" __declspec(dllexport) Foo *MyFunc(Foo *param)
{
param = new Bar();
delete param;
return param;
}
The program is still crashing in the delete param operation in the same place.
It looks like the destructor of the std::vector is called later, after the destructor of Foo is called. Is it how it suppose to be?
UPDATE2:
After carefully running this under debugger, I see that the crash happens inside "void operator delete(void *pUserData);". The pUserData pointer has an address of "param".
The DLL1 is built with this:
C++
/ZI /nologo /W4 /WX- /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\dll1.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue
Librarian /OUT:"C:\Users\Igor\OneDrive\Documents\dbhandler1\docview\Debug\dll1.lib" /NOLOGO
The DLL2 was built with:
C++
/I"..\dll1\" /Zi /nologo /W4 /WX- /Od /Oy- /D "WIN32" /D "_USRDLL" /D "DLL_EXPORTS" /D "_DEBUG" /D "_CRT_SECURE_NO_DEPRECATE=1" /D "_CRT_NON_CONFORMING_SWPRINTFS=1" /D "_SCL_SECURE_NO_WARNINGS=1" /D "_UNICODE" /D "MY_DLL_BUILDING" /D "_WINDLL" /D "UNICODE" /Gm- /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /Fp"vc_mswud\dll2\dll2.pch" /Fa"vc_mswud\dll2\" /Fo"vc_mswud\dll2\" /Fd"vc_mswud\dll2.pdb" /Gd /analyze- /errorReport:queue
Linker
/OUT:"..\myapp\vc_mswud\dll2.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\docview\Debug\" /DLL "dll1.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "comdlg32.lib" "winspool.lib" "winmm.lib" "shell32.lib" "shlwapi.lib" "comctl32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "rpcrt4.lib" "advapi32.lib" "version.lib" "wsock32.lib" "wininet.lib" /MANIFEST /ManifestFile:"vc_mswud\dll2\dll2.dll.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"vc_mswud\dll2.pdb" /PGD:"C:\Users\Igor\OneDrive\Documents\myapp\dll2\vc_mswud\dll2.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"vc_mswud\dll2.lib" /MACHINE:X86 /ERRORREPORT:QUEUE
Does anybody see any issues with the way my libraries are built?
Foo
because the compiler-generated copy constructor will perform a shallow copy ofpimpl
, leading to a double-delete. – SthenoFoo
. It's not clear whether you are following guidelines for memory allocation and freeing with DLLs. Specifically, whoever allocatedFoo
should freeFoo
. Is this the case? – Lashelllasherpimpl
toNULL
inFoo
's destructor. The object is going away, sopimpl
goes away, too. – PassivismBase
in the code you posted, so failures stepping out of its destructor are very hard to help with. – CrucialNULL
on a copy. Try to disable (=delete
) or implement the copy constructor and see what happens. – Sthenoclass Base
in the posted code. – Crucialdll1.dll!Foo::`vector deleting destructor'
is not the std::vector destructor. It's the 'final clean-up code' of Foo, so the code that runs right after the written code of~Foo
completes. This is an internal detail of the Visual C++ object model. – CrucialImpl* pImpl
with a simplebool
, the same behaviour would happen. – Crucial