故事:我正在创建一个共享库,将C代码公开为VS 2008中编译的C ++静态库的包装器,因此我与该编译器绑定。在我的库中,我试图做一个非常简单的字典来通过共享库边界传递数据。我不会传递实际的字典,只是提供访问其成员的函数的处理程序。字典只是键值对的std :: vector。
问题:每次尝试将键值对推送回字典时,我的程序都会崩溃。这是一个独立的演示代码(一个新的Win32控制台项目的main.cpp):
#include "stdafx.h"
#include <cstdlib>
#include <vector>
typedef enum KeyType
{
KeyType_CHAR = 0,
KeyType_INT,
KeyType_CHAR_PTR_AS_STRING
};
typedef enum ValueType
{
ValueType_CHAR = 0,
ValueType_INT,
ValueType_CHAR_PTR_AS_STRING
};
struct DictNode
{
ValueType value_type;
void* value_unsafe_ptr;
void* key_unsafe_ptr;
};
struct Dict
{
KeyType key_type;
std::vector<DictNode> nodes;
};
int _tmain(int argc, _TCHAR* argv[])
{
/* Create Dict */
Dict* test = (Dict*)malloc(sizeof(Dict));
test->key_type = KeyType_INT;
/* Add (0, "Zero") */
int* key0 = (int*)malloc(sizeof(int));
*key0 = 0;
char* content0 = (char*)malloc(sizeof(char)*5);
content0[0] = 'Z';
content0[1] = 'e';
content0[2] = 'r';
content0[3] = 'o';
content0[4] = '\0';
DictNode node0;
node0.value_type = ValueType_CHAR;
node0.key_unsafe_ptr = key0;
node0.value_unsafe_ptr = content0;
test->nodes.push_back(node0); // BOOM
/* Release memory */
test->nodes.clear();
free(key0);
free(content0);
free(test);
return 0;
}
在第test->nodes.push_back(node0);
行,我得到0xC0000005: Access violation reading location 0xcdcdcdc1
。通过在该行设置断点,我可以看到所有key
,content0
,node0和test
都已定义并拥有correct values。
答案 0 :(得分:3)
Dict* test = (Dict*)malloc(sizeof(Dict));
没有按照您的想法行事。
malloc
分配一块内存,但不初始化它。所以稍后,当你调用test->nodes.push_back
时,你会调用未初始化的内存。未定义的行为。在你的情况下,它崩溃了。
此处的解决方案是使用test
分配new
,这将初始化test
和test->nodes
。
Dict* test = new Dict;
更好的解决方案是询问为什么test
动态分配为开始。
答案 1 :(得分:1)
由于您使用C来分配内容,因此您无法获得C ++初始化行为。
因此,当您分配Dict
时,std::vector
仍然完全未初始化。您无法在不首先初始化的情况下使用它。只要您不想实际使用C ++,就应该使用placement new。
正确的解决方案是用C ++编程=&gt;使用new
代替malloc
。另外,除非你真的需要,否则不要将东西存储在堆上是一个好主意。
所以快速解决方法是添加:
new (&(test->nodes)) std::vector<DictNodes>;
分配测试后。
更好的方法是完全停止使用malloc
并使用
Dict *test = new Dict; // this automatically initializes the vector
或可能
Dict test; // no need to allocate on the heap if you don't need to