std::vector push_back 导致访问冲突

std::vector push_back results in access Violation

故事: 我正在制作一个共享库,将 C 代码作为包装器公开到在 VS 2008 中编译的 C++ 静态库,所以我依赖于该编译器。在我的图书馆中,我正在尝试制作一个非常简单的字典来通过共享图书馆边界传递数据。我不会传递实际的字典,只传递处理程序并提供访问其成员的函数。字典只是一个 std::vector 键值对。

问题: 每次尝试将键值对 push_back 放入字典时,我的程序都会崩溃。这是一个独立的演示代码(main.cpp 一个新的 Win32 控制台项目):

#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] = '[=12=]';

    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。通过在该行设置断点,我可以看到所有 keycontent0、node0 和 test 都已定义并具有 correct values.

由于您使用 C 来分配内容,因此您不会获得 C++ 初始化行为。

因此,当您分配 Dict 时,std::vector 仍未完全初始化。如果不先初始化它就不能使用它。只要您不想实际使用 C++,就应该为此使用 placement new。

正确的解决方案是用 C++ 编程 => 使用 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

Dict* test = (Dict*)malloc(sizeof(Dict)); 并不像您想象的那样。

malloc 分配一块内存,但不初始化它。所以稍后,当您调用 test->nodes.push_back 时,您正在调用未初始化的内存。未定义的行为。在你的情况下,它崩溃了。

这里的解决方案是用 new 分配 test,这将同时初始化 testtest->nodes

Dict* test = new Dict;

更好的解决方案是询问为什么 test 是动态分配的。