Difference in byte-size of STL-containers in Visua

2019-07-16 17:17发布

I am working in a solution with projects of both VS2010 and VS2012.

The VS2010 project calls functions in VS2012 and vice-versa. This worked fine at first, but when I also needed to share variables between both projects I noticed variables doesn't seem to have the same memory alignments and each project interprets the same memory address differently.

Update: It only seems to occur when using STL-containers, other structs and classes which doesn't contain std:: works fine.

To illustrate the problem, the following code should yeld different results when run on different Visual Studio versions.

#include <string>
#include <vector>

int main()
{
    int stringSize = sizeof(std::string);           // Yelds 32 on VS2010, 28 on VS2012
    int intVectorSize = sizeof(std::vector<int>);   // Yelds 20 on VS2010, 16 on VS2012

    return 0;
};

Updating both projects to the same version is not possible for me yet as I have a few dependencies tied to each version.

Does anyone know of a solution or a way to bypass the problem?

I will upgrade both project to the VS2012 compiler as soon as it's possible, but right now I'm hopping for a quick and dirty solution so I just can get along with working. Since it only seems to occur with STL-containers, is it perhaps possible to use an older version of the library on all projects? Or is it possible to fool the compiler? Perhaps changing the padding size?

Also, the first element in a std::vector seems to read fine, only subsequent elements in the vector seems to get scrambled. (See picture.)

Debug Image

Image of debugging the "Fetched" variable in "main.cpp" compiled in both 2010 and 2012.


Someone wanted me to clarify the way variables is being shared.

We are compiling the first project into a DLL in VS2012 compile mode and then trying to access that one in VS2010.

Here's some code to recreate the problem. If you would like to try for yourself you can download the full VS2012 solution here.

This code is compiled into a DLL using VS2012.

DllExport.h

#ifdef DLLHELL_EX
#define DLL_API __declspec(dllexport) 
#else
#define DLL_API __declspec(dllimport) 
#endif

#include <vector>
#include <string>

class DLL_API Foo
{
public:
    Foo();
    ~Foo();

    std::vector<std::string>* exposedMember;
};

DllExport.cpp

#include "DllExport.h"

Foo::Foo()
{
    // Create member
    exposedMember = new std::vector<std::string>();

    // Fill member with juicy data
    for(int i=0; i<5; i++)
            exposedMember->push_back("Fishstick");
}

Foo::~Foo()
{
    // Clean up behind ourselves like good lil' programmers
    delete exposedMember;
}

This code uses the DLL and is compiled using VS2010.

main.cpp

#include "DllExport.h"

int main()
{
    // Creating class from DLL
    Foo bar;

    // Fetching "exposedMember" from class
    std::vector<std::string>* member = bar.exposedMember;

    return 0;
}

The DLL was created, using this tutorial

2条回答
ら.Afraid
2楼-- · 2019-07-16 17:29

Since I don't have the option of not using different versions, the closest to solving the problem I think is by using pointers to STL-containers instead of accessing them directly (e.g. std::vector<std::string*>* instead of std::vector<std::string>*).

I would still very much prefer a non-pointer solution if it is possible, but at least this way I won't have to invent my own string and vector-class as a workaround.

Pointers inside visual studio


Update

People apparently didn't very much like this answer. Personally I think it's better being told there is a solution rather than being told something should not be done at all. The solution saved us as it allowed us to continue working until we could upgrade everything to the same compiler a few weeks later.

Although, the criticism has some merits. The solution although working could be very dangerous and it is probably a coincidence that the layout of the String class is identical in both compilers when allocated alone rather than as part of a struct.

A better solution would probably simply be:

Use C types instead, e.g. use .c_str() to expose a C string instead of accessing you string-directly from the DLL or replace all your strings with C strings.

I now think this is what @CoryNelson meant with most people choose to export only C types, but due to my ignorance and inexperience with C-types at the time, I didn't understand this, and I thought I was simply being told it was not possible and I was stupid for trying.

Also for people down-voting it would be greatly appreciated if you provided an explanation as to why instead of me having to guess on my own. I have no problem with criticism as long as a reason is given.

查看更多
做个烂人
3楼-- · 2019-07-16 17:37

You absolutely should not mix types from different versions of the runtime. Even if they are the same size, they might store variables in different locations, or some algorithm might slightly change. Even if the types are exactly the same, different compilers might choose to represent them differently.

There really is no good way to do this. C++ doesn't guarantee the implementation of its standard library won't change, and compilers can't seem to agree on an ABI (even between versions of the same compiler) even if they didn't. When writing APIs for others to consume, most people choose to export only C types which are entirely under their control.

查看更多
登录 后发表回答