通过指针或引用访问STL对象时访问冲突在不同的DLL或EXE中 [英] Access Violation When Accessing an STL Object Through A Pointer or Reference In A Different DLL or EXE

查看:129
本文介绍了通过指针或引用访问STL对象时访问冲突在不同的DLL或EXE中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用旧版VC6时遇到以下问题。我只是无法切换到现代编译器,因为我正在开发一个旧代码库。



http://support.microsoft.com/kb/172396



由于没有办法导出地图,我的计划解决方法是使用静态链接而不是动态链接。



我想知道你是否都遇到过类似的情况?你的解决方法是什么?



另一个解决方法是在stl映射周围创建包装类,以确保创建和访问stl映射,在同一个DLL空间中。注意,fun0,它使用包装类将只是工作正常。



以下是代码示例:

  / main.cpp。编译为exe。 
#pragma warning(disable:4786)
#include< map>
#include< string>

template< class K,class V>
class __declspec(dllimport)map_wrapper {
public:
map_wrapper();
〜map_wrapper();
map_wrapper(const map_wrapper&);
map_wrapper& operator =(const map_wrapper&);

V& operator [](const K&);
const V& operator [](const K&)const;

const V& get(const K&)const;
void put(const K& const V&);
int size()const;

private:
std :: map< K,V> * m;
};

__declspec(dllimport)void fun0(map_wrapper< std :: string,int>& m);
__declspec(dllimport)void fun1(std :: map< std :: string,int>& m);

int main(){
map_wrapper< std :: string,int> m0;
std :: map< std :: string,int> m1;

m0 [hello] = 888;
m1 [hello] = 888;

//安全。我们在dll空间中创建std :: map和访问映射。
fun0(m0);
//崩溃!我们在exe空间中创建std :: map,并在dll空间中访问映射。
fun1(m1);

return 0;
}






  // dll.cpp。编译为动态dll。 
#pragma warning(disable:4786)
#include< map>
#include< string>
#include< iostream>

/ *在map_wrapper.h * /
模板< class K,class V>
class __declspec(dllexport)map_wrapper {
public:
map_wrapper();
〜map_wrapper();
map_wrapper(const map_wrapper&);
map_wrapper& operator =(const map_wrapper&);

V& operator [](const K&);
const V& operator [](const K&)const;

const V& get(const K&)const;
void put(const K& const V&);
int size()const;

private:
std :: map< K,V> * m;
};
/ * End * /

/ *在map_wrapper.cpp * /
模板中< class K,class V>
map_wrapper< K,V> :: map_wrapper():m(new std :: map< K,V>()){
}

template& ,V类>
map_wrapper< K,V> ::〜map_wrapper(){
delete m;
}

template< class K,class V>
map_wrapper< K,V> :: map_wrapper(const map_wrapper< K,V& map):m(new std :: map< K,V& $ b}

template< class K,class V>
map_wrapper< K,V>& map_wrapper< K,V> :: operator =(const map_wrapper< K,V& map){
std :: map< K,V> * tmp = this-&
this-> m = new std :: map< K,V>(*(map.m));
delete tmp;
return * this;
}

template< class K,class V>
V& map_wrapper< K,V> :: operator [](const K& key){
return(* this-> m)[key]
}

template< class K,class V>
const V& map_wrapper< K,V> :: operator [](const K& key)const {
return(* this-> m)[key]
}

template< class K,class V>
const V& map_wrapper< K,V> :: get(const K& key)const {
return(* this-> m)[key]
}

template< class K,class V>
void map_wrapper< K,V> :: put(const K& key,const V& value){
(* this-> m)
}

template< class K,class V>
int map_wrapper< K,V> :: size()const {
return this-> m-> size();
}

//参见:http://www.parashift.com/c++-faq-lite/templates.html#faq-35.15
// [35.15]如何我可以避免链接器错误与我的模板类吗?
template class __declspec(dllexport)map_wrapper< std :: string,int> ;;
/ * End * /

__declspec(dllexport)void fun0(map_wrapper< std :: string,int>& m){
std :: cout< m [hello]< std :: endl;
}

__declspec(dllexport)void fun1(std :: map< std :: string,int>& m){
std :: cout< m [hello]< std :: endl;
}


解决方案

老,它是在VS2008出来之前写的。它不解决问题,它是C ++的一个根本限制。没有机制来验证单独构建的二进制中的类具有兼容的内存布局,并且分配了相同的内存分配器。



您可以执行以下操作来避免此问题: / p>


  • 避免导出类对象

  • 使用/ MD构建DLL和EXE,内存分配器

  • 使用相同的编译器和CRT版本构建所有DLL和EXE

  • 仔细控制构建设置, ,项目属性表是确保这一点的最佳方式。


I experience the following problem while using legacy VC6. I just cann't switch to modern compiler, as I am working on a legacy code base.

http://support.microsoft.com/kb/172396

Since there are no way to export map, my planned workaround is using static linking instead of dynamic linking.

I was wondering whether you all had encountered the similar situation? What is your workaround for this?

Another workaround is to create wrapper class around the stl map, to ensure creation and accessing stl map, are within the same DLL space. Note that, fun0, which uses wrapper class will just work fine. fun1 will crash.

Here is the code example :

// main.cpp. Compiled it as exe.
#pragma warning (disable : 4786)
#include <map>
#include <string>

template <class K, class V>
class __declspec(dllimport) map_wrapper {
public:
    map_wrapper();
    ~map_wrapper();    
    map_wrapper(const map_wrapper&);
    map_wrapper& operator=(const map_wrapper&);

    V& operator[](const K&); 
    const V& operator[](const K&) const;

    const V& get(const K&) const;
    void put(const K&, const V&);
    int size() const;

private:
    std::map<K, V> *m;
};

__declspec(dllimport) void fun0(map_wrapper<std::string, int>& m);
__declspec(dllimport) void fun1(std::map<std::string, int>& m);

int main () {
    map_wrapper<std::string, int> m0;
    std::map<std::string, int> m1;

    m0["hello"] = 888;
    m1["hello"] = 888;

    // Safe. The we create std::map and access map both in dll space.
    fun0(m0);
    // Crash! The we create std::map in exe space, and access map in dll space.
    fun1(m1);

    return 0;
}


// dll.cpp. Compiled it as dynamic dll.
#pragma warning (disable : 4786)
#include <map>
#include <string>
#include <iostream>

/* In map_wrapper.h */
template <class K, class V>
class __declspec(dllexport) map_wrapper {
public:
    map_wrapper();
    ~map_wrapper();    
    map_wrapper(const map_wrapper&);
    map_wrapper& operator=(const map_wrapper&);

    V& operator[](const K&); 
    const V& operator[](const K&) const;

    const V& get(const K&) const;
    void put(const K&, const V&);
    int size() const;

private:
    std::map<K, V> *m;
};
/* End */

/* In map_wrapper.cpp */
template <class K, class V>
map_wrapper<K, V>::map_wrapper() : m(new std::map<K, V>()) {
}

template <class K, class V>
map_wrapper<K, V>::~map_wrapper() {
    delete m;
}

template <class K, class V>
map_wrapper<K, V>::map_wrapper(const map_wrapper<K, V>& map) : m(new std::map<K, V>(*(map.m))) {
}

template <class K, class V>
map_wrapper<K, V>& map_wrapper<K, V>::operator=(const map_wrapper<K, V>& map) {
    std::map<K, V>* tmp = this->m;
    this->m = new std::map<K, V>(*(map.m));
    delete tmp;
    return *this;
}

template <class K, class V>
V& map_wrapper<K, V>::operator[](const K& key) {
    return (*this->m)[key];
}

template <class K, class V>
const V& map_wrapper<K, V>::operator[](const K& key) const {
    return (*this->m)[key];
}

template <class K, class V>
const V& map_wrapper<K, V>::get(const K& key) const {
    return (*this->m)[key];
}

template <class K, class V>
void map_wrapper<K, V>::put(const K& key, const V& value) {
    (*this->m)[key] = value;
}

template <class K, class V>
int map_wrapper<K, V>::size() const {
    return this->m->size();
}

// See : http://www.parashift.com/c++-faq-lite/templates.html#faq-35.15
// [35.15] How can I avoid linker errors with my template classes?
template class __declspec(dllexport) map_wrapper<std::string, int>;
/* End */

__declspec(dllexport) void fun0(map_wrapper<std::string, int>& m) {
    std::cout << m["hello"] << std::endl;
}

__declspec(dllexport) void fun1(std::map<std::string, int>& m) {
    std::cout << m["hello"] << std::endl;
}

解决方案

The KB article you linked is old, it was written before VS2008 came out. It doesn't solve the problem, it is a fundamental limitation of C++. There is no mechanism to verify that classes in separately built binaries have compatible memory layouts and were allocated with the same memory allocator.

Things you can do to avoid the problem:

  • avoid exporting class objects
  • build your DLLs and EXE with /MD so they'll share the memory allocator
  • build all DLLs and EXE with the same compiler and CRT version
  • carefully control the build settings to ensure they are the same for all projects, project property sheets are the best way to ensure this.

这篇关于通过指针或引用访问STL对象时访问冲突在不同的DLL或EXE中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆