使用自定义工具集获取动态atexit析构函数链接错误 - 呃vector destructor

时间:2017-07-02 14:54:35

标签: c++ visual-studio-2015 linker-errors lnk2019 msvcrt

尝试使用Visual Studio 2015工具集针对VS2005 CRT进行编译时,我收到了一个奇怪的链接器错误。
相同的代码在任何其他工具集版本(2005,2010,2012,2013)上编译完美 代码必须在VS2005 CRT下编译才能与其他项目正确链接。

如何重现: 创建一个新的空动态库(dll)项目(在VS2015中,工具集v140),添加一个源(.cpp)文件:

//1.cpp
#include <string>

static  std::wstring thisWillFail[] = { L"test" };

将VC ++ include目录和Library目录更改为:

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\include
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\include

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\lib
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\lib
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\Lib

然后编译,你会得到这个错误:

1>StdAfx.obj : error LNK2019: unresolved external symbol "void __stdcall `eh vector destructor iterator'(void *,unsigned int,unsigned int,void (__thiscall*)(void *))" (??_M@YGXPAXIIP6EX0@Z@Z) referenced in function "void __cdecl `dynamic atexit destructor for 'fasdfp''(void)" (??__Ffasdfp@@YAXXZ)

如果您设置库并包含VS2010 CRT和Windows SDK的路径,也会发生同样的情况。

那么,为什么VS2015会产生这个额外的功能呢?最重要的是我如何解决这个问题? 我拥有的每个静态成员都会出现相同的链接器错误,而且对于几个类,也会出现类似的链接器错误。

1 个答案:

答案 0 :(得分:3)

在VS2015中有一个专业refactoring in the CRT 部分原因是改变了实施,以及__ehvec_dtor的签名 作为mentioned here,一个简单的解决方案就是添加实际的实现。

最简单的方法是将此代码添加到头文件中并将其包含在stdafx.h中:

#if defined __cplusplus_cli
#define CALEETYPE __clrcall
#else
#define CALEETYPE __stdcall
#endif
#define __RELIABILITY_CONTRACT
#define SECURITYCRITICAL_ATTRIBUTE
#define ASSERT_UNMANAGED_CODE_ATTRIBUTE

#if defined __cplusplus_cli
#define CALLTYPE __clrcall 
#elif defined _M_IX86
#define CALLTYPE __thiscall
#else
#define CALLTYPE __stdcall
#endif

__RELIABILITY_CONTRACT
void CALEETYPE __ArrayUnwind(
    void*       ptr,                // Pointer to array to destruct
    size_t      size,               // Size of each element (including padding)
    int         count,              // Number of elements in the array
    void(CALLTYPE *pDtor)(void*)    // The destructor to call
    );

__RELIABILITY_CONTRACT
inline void CALEETYPE __ehvec_ctor(
    void*       ptr,                // Pointer to array to destruct
    size_t      size,               // Size of each element (including padding)
    //  int         count,              // Number of elements in the array
    size_t      count,              // Number of elements in the array
    void(CALLTYPE *pCtor)(void*),   // Constructor to call
    void(CALLTYPE *pDtor)(void*)    // Destructor to call should exception be thrown
    ) {
    size_t i = 0;      // Count of elements constructed
    int success = 0;

    __try
    {
        // Construct the elements of the array
        for (; i < count; i++)
        {
            (*pCtor)(ptr);
            ptr = (char*)ptr + size;
        }
        success = 1;
    }
    __finally
    {
        if (!success)
            __ArrayUnwind(ptr, size, (int)i, pDtor);
    }
}

__RELIABILITY_CONTRACT
SECURITYCRITICAL_ATTRIBUTE
inline void CALEETYPE __ehvec_dtor(
    void*       ptr,                // Pointer to array to destruct
    size_t      size,               // Size of each element (including padding)
    //  int         count,              // Number of elements in the array
    size_t      count,              // Number of elements in the array
    void(CALLTYPE *pDtor)(void*)    // The destructor to call
    ) {
    _Analysis_assume_(count > 0);

    int success = 0;

    // Advance pointer past end of array
    ptr = (char*)ptr + size*count;

    __try
    {
        // Destruct elements
        while (count-- > 0)
        {
            ptr = (char*)ptr - size;
            (*pDtor)(ptr);
        }
        success = 1;
    }
    __finally
    {
        if (!success)
            __ArrayUnwind(ptr, size, (int)count, pDtor);
    }
}