2016-02-10 21 views
7

Ich versuche, die DLL zu testen, die ich mit GoogleTest schrieb und als ich einen der Tests rufen Sie werfen mir diesen Fehler:Debug-Assertion fehlgeschlagen! Expression: __acrt_first_block == Header

enter image description here

Ich bin zu dem Schluss gekommen, dass Das Problem liegt in der Zuweisung von Speicher zu Vektoren, aber ich weiß nicht, wie ich das lösen soll, da ich ziemlich neu in der C++ Programmierung bin. Der Code ist wie folgt:

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

Sie haben * undefiniertes Verhalten * in Ihrem Code. Sie haben eine leere Zeichenfolge im 'start2'-Vektor, die Sie schließlich an die' removeWhiteSpace'-Funktion übergeben, wo Sie auf das erste Zeichen der Zeichenfolgen im Vektor zugreifen. Wenn eine Zeichenfolge leer ist, enthält sie kein erstes Zeichen. Daher indexieren Sie außerhalb der Grenzen. Auch der Name 'removeWhiteSpace' ist nicht sehr gut, da die Funktion nicht wirklich Leerzeichen entfernt, sondern nur überprüft, ob das erste Zeichen einer Zeichenkette eine Ziffer ist oder nicht (falsch wie ich gerade bemerkt habe). –

+0

@JoachimPilebog Der Vektor 'start2' wird hauptsächlich zum Debuggen des Vergleichsteils des Tests verwendet (der Teil des Codes, der nach dem Aufruf von' removeWhiteSpaces' steht) und wird entfernt, nachdem ich das Problem behoben habe. Auch die Funktion 'removeWhiteSpaces' entfernt tatsächlich den Leerraum, da nur die Elemente, die Ziffern sind, in einen neuen Vektor geschoben werden. – Rok

+0

Btw. Warum kopierst du die Vektoren überall anstatt sie durch const zu übergeben (zum Beispiel in 'removeWhiteSpaces (std :: vector v, ...)' 'wo du nur auf den Vektor v schaust, also muss er nicht sein nicht-const). – axalis

Antwort

15

Da dies eine DLL ist, liegen könnte das Problem in verschiedenen Haufen für die Zuordnung verwendet und Freigabe (versuchen Sie die Bibliothek statisch zu bauen und prüfen, ob das wird funktionieren).

Das Problem ist, dass DLLs und Vorlagen nicht sehr gut miteinander übereinstimmen. Im Allgemeinen kann es abhängig von der Verknüpfung der MSVC-Laufzeit problematisch sein, wenn der Speicher in der ausführbaren Datei zugeordnet und in der DLL freigegeben wird (und umgekehrt) (weil sie möglicherweise unterschiedliche Heaps haben). Und das kann mit Vorlagen sehr leicht passieren, zum Beispiel: Sie push_back() zu dem Vektor innerhalb der removeWhiteSpaces() in der DLL, so dass der Vektorspeicher innerhalb der DLL zugeordnet ist. Dann verwenden Sie den Ausgabevektor in der ausführbaren Datei und sobald er den Gültigkeitsbereich verlässt, wird er freigegeben, aber innerhalb der ausführbaren Datei, deren Heap nichts über den Heap weiß, von dem er zugewiesen wurde. Bang, du bist tot.

Dies kann ausgeführt werden, wenn DLL und die ausführbare Datei den gleichen Heap verwenden. Um dies zu gewährleisten, müssen sowohl die DLL als auch die ausführbare Datei die dynamische MSVC-Laufzeit verwenden. Stellen Sie daher sicher, dass beide dynamisch und nicht statisch mit der Laufzeit verbunden sind. Insbesondere sollte die exe mit/MD [d] und die Bibliothek mit/LD [d] oder/MD [d] ebenfalls kompiliert und verknüpft werden, keines mit/MT [d]. Beachten Sie, dass der Computer, auf dem die Anwendung ausgeführt wird, anschließend die MSVC-Laufzeitbibliothek ausführen muss (z. B. durch Installieren von "Visual C++ Redistributable" für die jeweilige MSVC-Version).

Sie könnten diese Arbeit sogar mit/MT bekommen, aber das ist schwieriger - Sie müssten eine Schnittstelle zur Verfügung stellen, die es erlaubt, auch die in der DLL zugewiesenen Objekte freizugeben. Zum Beispiel so etwas wie:

__declspec(dllexport) void deallocVector(std::vector<std::string> &x); 

void deallocVector(std::vector<std::string> &x) { 
    std::vector<std::string> tmp; 
    v.swap(tmp); 
} 

(aber nicht sehr gut in allen Fällen funktioniert, wie dies explizit aufgerufen werden muss, damit es nicht zum Beispiel im Fall einer Ausnahme aufgerufen wird - dies richtig zu lösen, würden Sie muss eine Schnittstelle von der DLL zur Verfügung stellen, die den Vektor unter der Haube bedeckt und wird sich um die richtige RAII kümmern)

EDIT: die endgültige Lösung war eigentlich, alle Projekte zu haben (die exe, dll und das gesamte googleTest-Projekt) in Multi-threaded Debug-DLL (/ MDd) (die GoogleTest-Projekte sind in Multi-Threaded Debug (/ MTd) standardmäßig erstellt)

+0

Ich werde versuchen, aber leider am Ende muss ich einen Weg finden, um es als DLL arbeiten, wie mein Vorgesetzter es so will – Rok

+0

Aktualisiert die Antwort, müssen Sie im Grunde gegen die dynamische Laufzeit zu verknüpfen, um diese Art zu vermeiden von Problemen. – axalis

+0

also, wenn ich richtig verstehe, muss ich die Laufzeitbibliothek der exe auf/MD und die der DLL auf/LD richtig? Wenn ja, kann ich das nicht wirklich für die DLL tun, weil die Option/LD mir nicht gegeben wird. – Rok