调试断言失败!表达式:__acrt_first_block == 标题
我正在尝试测试我用 GoogleTest 编写的 dll,当我调用其中一个测试时,它抛出了这个错误:
I am trying to test the dll which I wrote with GoogleTest and when I call one of the tests It throws me this error:
我得出的结论是问题在于为向量分配内存,但我不知道如何解决这个问题,因为我对 C++ 编程还很陌生.代码如下:
I have come to the conclusion that the problem is in assigning memory to vectors but I don't know how to resolve this as I am fairly new to C++ programming. The code is as follows:
#ArraysCPP11.h
#ifdef ARRAYSCP11_EXPORTS
#define ARRAYSCP11_API __declspec(dllexport)
#else
#define ARRAYSCP11_API __declspec(dllimport)
#endif
__declspec(dllexport) void removeWhiteSpaces(std::vector<std::string> v, std::vector<std::string> &output);
#ArraysCPP11.cpp
void removeWhiteSpaces(std::vector<std::string> v, std::vector<std::string> &output) { //odstranjevanje presledkov iz vector-ja (vsak drugi element je bil presledek)
for (std::vector<std::string>::iterator it = v.begin(); it != v.end(); it++) {
std::string buffer = *it;
if (isdigit(buffer[0])){;
output.push_back(*it);
}
}
}
#TestTemp.h
template<class T>
class TestTemp
{
public:
TestTemp();
void SetValue(T obj_i);
T GetValue();
bool alwaysTrue();
bool TestTemp<T>::formattingTest(std::string input, std::vector<std::string> realVector, std::vector<std::string> formattedInput);
private:
T m_Obj;
};
template<class T>
inline bool TestTemp<T>::formattingTest(std::string input, std::vector<std::string> realVector, std::vector<std::string> formattedVector) {
std::string input2 = input;
// std::vector<std::string> fResult;
std::string first;
std::string second;
bool endResult = true;
std::vector<std::string> end;
//std::vector<std::string> result = split(input2, ' ');
removeWhiteSpaces(formattedVector,end);
std::vector<std::string>::iterator yt = realVector.begin();
for (std::vector<std::string>::iterator it = end.begin(); it != end.end(); it++, yt++) {
first = *it;
second = *yt;
if (first.compare(second) != 0) {
endResult = false;
break;
}
}
return endResult;
}
#ArraysCPP11-UnitTest.cpp
struct formattingTesting{
// formattingTesting* test;
std::string start;
std::vector<std::string> endResult;
formattingTesting() {
}
explicit formattingTesting(const std::string start, const std::vector<std::string> endResult)
: start{start}, endResult{endResult}
{
}
};
struct fTest : testing::Test {
formattingTesting* test;
fTest() {
test = new formattingTesting;
}
~fTest() {
delete test;
}
};
struct format {
std::string start;
std::vector<std::string> end;
};
struct formTest : fTest, testing::WithParamInterface<format> {
formTest() {
test->start = GetParam().start;
test->endResult = GetParam().end;
}
};
TEST_P(formTest, test1) {
bool endResult = true;
TestTemp<int> TempObj;
std::string first;
std::string second;
//std::string start ("1 2 3 4 5 6 7 8 9 10");
//std::vector<std::string> end = { "1","2","3","4","5","6","7","8","9","10" };
std::vector<std::string> start2 = { "1","","2","3","4","5","6","7","8","9","10" };
std::string start = GetParam().start;
std::vector<std::string> end = GetParam().end;
bool result = TempObj.formattingTest(start,end,start2);
EXPECT_TRUE(result);
}
INSTANTIATE_TEST_CASE_P(Default, formTest, testing::Values(
format{ "1", {"1"} },
format{ " ", {} },
format{ "1 2 3 4 5",{"1","2","3","4","5"} },
format{ "1 2 3 4 5 6", {"1","2","3","4","5","6"} }
));
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
return 0;
}
推荐答案
由于这是一个 DLL,问题可能在于用于分配和解除分配的不同堆(尝试静态构建库并检查这是否可行).
As this is a DLL, the problem might lie in different heaps used for allocation and deallocation (try to build the library statically and check if that will work).
问题是,DLL 和模板不能很好地配合在一起.通常,根据 MSVC 运行时的链接,如果内存在可执行文件中分配并在 DLL 中释放,反之亦然(因为它们可能具有不同的堆),则可能会出现问题.这很容易在模板中发生,例如:您将 push_back() 推送到 DLL 中 removeWhiteSpaces() 内的向量,因此向量内存在 DLL 内分配.然后你在可执行文件中使用输出向量,一旦它超出范围,它就会被释放,但是在可执行文件中,它的堆不知道它已经分配的堆的任何信息.砰,你死定了.
The problem is, that DLLs and templates do not agree together very well. In general, depending on the linkage of the MSVC runtime, it might be problem if the memory is allocated in the executable and deallocated in the DLL and vice versa (because they might have different heaps). And that can happen with templates very easily, for example: you push_back() to the vector inside the removeWhiteSpaces() in the DLL, so the vector memory is allocated inside the DLL. Then you use the output vector in the executable and once it gets out of scope, it is deallocated, but inside the executable whose heap doesn't know anything about the heap it has been allocated from. Bang, you're dead.
如果 DLL 和可执行文件使用相同的堆,这可以解决.为确保这一点,DLL 和可执行文件都必须使用动态 MSVC 运行时 - 因此请确保两者都动态链接到运行时,而不是静态链接.特别是,exe 应该用/MD[d] 编译和链接,库也应该用/LD[d] 或/MD[d] 来编译和链接,两者都不能用/MT[d].请注意,之后将运行该应用程序的计算机将需要运行 MSVC 运行时库(例如,通过为特定 MSVC 版本安装Visual C++ Redistributable").
This can be worked-around if both DLL and the executable use the same heap. To ensure this, both the DLL and the executable must use the dynamic MSVC runtime - so make sure, that both link to the runtime dynamically, not statically. In particular, the exe should be compiled and linked with /MD[d] and the library with /LD[d] or /MD[d] as well, neither one with /MT[d]. Note that afterwards the computer which will be running the app will need the MSVC runtime library to run (for example, by installing "Visual C++ Redistributable" for the particular MSVC version).
您甚至可以使用/MT 来完成这项工作,但这更困难 - 您需要提供一些接口,以允许在 DLL 中分配的对象也可以在那里解除分配.例如类似:
You could get that work even with /MT, but that is more difficult - you would need to provide some interface which will allow the objects allocated in the DLL to be deallocated there as well. For example something like:
__declspec(dllexport) void deallocVector(std::vector<std::string> &x);
void deallocVector(std::vector<std::string> &x) {
std::vector<std::string> tmp;
v.swap(tmp);
}
(但是这在所有情况下都不能很好地工作,因为这需要显式调用,因此在异常情况下不会被调用 - 为了正确解决这个问题,您需要从 DLL 中提供一些接口,它将覆盖引擎盖下的向量,并会处理正确的 RAII)
(however this does not work very well in all cases, as this needs to be called explicitly so it will not be called e.g. in case of exception - to solve this properly, you would need to provide some interface from the DLL, which will cover the vector under the hood and will take care about the proper RAII)
编辑:最终的解决方案实际上是将所有项目(exe、dll 和整个 googleTest 项目)都内置在 多线程调试 DLL (/MDd) 中强>(GoogleTest 项目默认内置多线程调试(/MTd))
EDIT: the final solution was actually was to have all of the projects (the exe, dll and the entire googleTest project) built in Multi-threaded Debug DLL (/MDd) (the GoogleTest projects are built in Multi-threaded debug(/MTd) by default)
相关文章