Разница в байтовом размере STL-контейнеров в Visual Studio 2010 и 2012

Я работаю в решении с проектами как VS2010, так и VS2012.

Проект VS2010 вызывает функции в VS2012 и наоборот. Сначала это работало нормально, но когда мне также нужно было делить переменные между обоими проектами, я заметил, что переменные не имеют одинакового выравнивания памяти, и каждый проект интерпретирует один и тот же адрес памяти по-разному.

Обновить:
Кажется, это происходит только при использовании STL-контейнеры, другие структуры и классы, которые не содержат std ::, работают нормально.

Чтобы проиллюстрировать проблему, следующий код должен давать разные результаты при запуске в разных версиях Visual Studio.

#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;
};

Обновление обоих проектов до одной и той же версии невозможно для меня пока, поскольку у меня есть несколько зависимостей, привязанных к каждой версии.

Кто-нибудь знает решение или способ обойти проблему?

Я обновлю оба проекта до компилятора VS2012, как только это станет возможным, но сейчас я собираюсь быстрое и грязное решение так что я просто могу ладить с работой. Поскольку кажется, что это происходит только с STL-контейнерами, возможно ли использовать старую версию библиотеки во всех проектах? Или возможно ли обмануть компилятор? Возможно, изменение размера отступов?

Также, первый элемент в std :: vector, кажется, читает хорошо, только последующий элементы в векторе, кажется, получают вскарабкался. (Смотрите картинку.)

Изображение отладки

Образ отладки переменной «Fetched» в «main.cpp», скомпилированный в 2010 и 2012 годах.


Кто-то хотел, чтобы я разъяснил, как переменные распределяются.

Мы компилируем первый проект в DLL в режиме компиляции VS2012, а затем пытаемся получить к нему доступ в VS2010.

Вот некоторый код, чтобы воссоздать проблему. Если вы хотите попробовать сами, вы можете загрузить полное решение VS2012 Вот.

Этот код скомпилирован в DLL с использованием 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;
}

Этот код использует DLL и скомпилирован с использованием 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;
}

DLL была создана с использованием этот руководство

2

Решение

Вы абсолютно не должны смешивать типы из разных версий среды выполнения. Даже если они имеют одинаковый размер, они могут хранить переменные в разных местах, или некоторые алгоритмы могут немного измениться. Даже если типы одинаковы, разные компиляторы могут представлять их по-разному.

Там действительно нет хорошего способа сделать это. C ++ не гарантирует, что реализация его стандартной библиотеки не изменится, и компиляторы не могут договориться о ABI (даже между версиями одного и того же компилятора), даже если они этого не сделали. При написании API для использования другими людьми, большинство людей предпочитают экспортировать только те типы C, которые полностью находятся под их контролем.

10

Другие решения

Поскольку у меня нет возможности не использовать разные версии, я думаю, что наиболее близким к решению проблемы является использование указателей на STL-контейнеры вместо прямого доступа к ним (например, std::vector<std::string*>* вместо std::vector<std::string>*).

Я бы еще очень предпочла без указателя решение, если это возможно, но, по крайней мере, таким образом мне не придется изобретать свою собственную строку и векторный класс в качестве обходного пути.

Указатели внутри визуальной студии


Обновить

Людям явно не очень понравился этот ответ. Лично я считаю, что лучше говорить, что есть решение, чем говорить, что вообще ничего не следует делать. Решение спасло нас, поскольку позволило нам продолжать работать, пока мы не смогли обновить все до того же компилятора несколько недель спустя.

Хотя у критики есть свои достоинства. Решение, хотя и работающее, может быть очень опасным, и, вероятно, совпадение заключается в том, что компоновка класса String идентична в обоих компиляторах при выделении по отдельности, а не как часть структуры.

Лучшее решение, вероятно, будет просто:

Вместо этого используйте типы C, например использование .c_str() вместо этого выставить строку C
доступа к строке непосредственно из DLL или заменить все ваши
Строки с C строк.

Теперь я думаю, что это то, что имел в виду @CoryNelson most people choose to export only C types, но из-за моего невежества и неопытности с С-типами в то время я этого не понимал, и мне показалось, что мне просто сказали, что это невозможно, и я был глуп, пытаясь это сделать.

Также для людей, проголосовавших за голосование, было бы очень признательно, если бы вы предоставили объяснение, почему вместо меня нужно угадывать самостоятельно. У меня нет проблем с критикой, если есть причина.

-2

По вопросам рекламы [email protected]