web-dev-qa-db-ja.com

デバッグアサーションに失敗しました!式:__acrt_first_block ==ヘッダー

私はGoogleTestで記述したdllをテストしようとしています。テストの1つを呼び出すと、次のエラーがスローされます。

enter image description here

私は問題がベクトルへのメモリの割り当てにあるという結論に達しましたが、私はC++プログラミングにかなり慣れていないため、これを解決する方法がわかりません。コードは次のとおりです。

#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;
}
20
Rok

これはDLLであるため、問題は割り当てと割り当て解除に使用される異なるヒープにある可能性があります(ライブラリを静的にビルドして、それが機能するかどうかを確認してください)。

問題は、DLLとテンプレートが非常によく一致しないことです。一般に、MSVCランタイムのリンケージによっては、メモリが実行可能ファイルに割り当てられ、DLL)で割り当てが解除された場合、またはその逆の場合(ヒープが異なる可能性があるため)、問題になる可能性があります。そして、それは非常に簡単にテンプレートで発生する可能性があります。たとえば、DLLのremoveWhiteSpaces()内のベクターにPush_back()を実行すると、ベクターメモリがDLL内に割り当てられます。次に、実行可能ファイルで出力ベクターを使用し、一度スコープ外になると、割り当てが解除されますが、割り当てられているヒープについてヒープが何も知らない実行可能ファイル内では、バン、あなたは死んでいます。

DLLと実行可能ファイルの両方が同じヒープを使用する場合、これを回避できます。これを確実にするには、DLLと実行可能ファイルの両方が動的MSVCを使用する必要がありますruntime-両方が静的ではなく動的にランタイムにリンクするようにしてください。特に、exeは/ MD [d]でコンパイルおよびリンクし、/ LD [d]または/ MD [d]でライブラリもリンクする必要があります。 、どちらも/ MT [d]を使用しない。その後、アプリを実行するコンピューターでMSVCランタイムライブラリを実行する必要があることに注意してください(たとえば、特定のMSVCバージョンの「Visual C++再頒布可能パッケージ」をインストールすることにより)。

/ MTを使用してもその動作を得ることができますが、これはより困難です。DLLに割り当てられたオブジェクトもそこで割り当て解除できるようにするインターフェイスを提供する必要があります。たとえば、何かのようなもの:

__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を処理します)


[〜#〜] edit [〜#〜]:最終的な解決策は、実際にはすべてのプロジェクト(exe、dll、およびgoogleTestプロジェクト全体)を組み込むことでしたMulti-スレッドデバッグDLL(/ MDd)(GoogleTestプロジェクトはデフォルトでマルチスレッドデバッグ(/ MTd)に組み込まれています)

35
axalis

同様の問題があり、ユニットテストプロジェクトが別のコード生成ランタイムライブラリに設定されていることがわかりました。DLLプロジェクトと同じに設定すると、ヒープ例外は発生しません。

3
serup

私もこのエラーを見ていました。私の場合、すべてのメモリモデル設定が正しく並んでいました。しかし、最近プロジェクトをvs2013からvs2015にアップグレードしたため、.exeと.dllの間に古い参照があったため、実際には2013年にビルドされた古いDLLを使用していました。参照を削除する必要がありました。 .exeと.dllの間に追加し、再度追加して、exeがリンクしていた.libの名前を更新します(.exeプロジェクトの[参照]子アイテムを右クリックして[追加]をクリックすると、混乱を招きます。参照を削除できます)。

1
fret

その検証は1992-1993にMicrosoftソフトウェア開発者によってかなり以前に実装されており、異種またはMPI新しいメモリのプログラミングは、ローカルヒープからではなく割り当てることができます。

アプリケーションがOpenCLまたはCUDA APIを使用してメモリを取得すると、GPUドライバーはすべてのメモリ割り当てを行います。もちろん、アプリケーションのローカルヒープは使用しません。ただし、アプリケーションは終了する前にメモリを解放する必要があります。その時点で、MicrosoftのMemory Leaks Detection APIがそれを検出し、そのアサートが表示されます。

その検証の起源については、ビデオテクニカルレポートをご覧ください。

MS Visual Studio 2015アサートの起源__acrt_first_block ==ヘッダー(VTR-010)https://www.youtube.com/watch? v = NJeA_YkLzxc

注:いくつかの修正を加えたビデオをアップロードしてから更新されたYouTubeビデオへのWebリンク。

1
Sergey Kostrov