ネコと和解せよ

C++(MSVC)で仮想継承したクラスのスマートポインタをダウンキャストして返すとCRTがエラーを吐く。。

表題通りのめんどくさいエラーに遭遇したのでメモ書きです。

開発環境はMSVCのMicrosoft Visual Studio Community 2022 (64 ビット) - Current Version 17.3.5です。

以下のように、仮想継承したクラスのunique_ptrをキャストして返すと、ヒープエラーを起こして死ぬことができます。

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <memory>
using namespace std;

class Base{};
class Extends : public virtual Base{};
unique_ptr<Base> CreatePointer()
{
	auto a = make_unique<Extends>();
	return a;
}
int main()
{
	{
		auto d = CreatePointer();
	}
	_CrtDumpMemoryLeaks();
	return 0;
}
HEAP[ConsoleApplication1.exe]: Invalid address specified to RtlValidateHeap( 0000014A9EA50000, 0000014A9EA61648 )
ブレークポイント命令 (__debugbreak() ステートメントまたは類似の呼び出し) が ConsoleApplication1.exe で実行されました。

Debug Assertion Failed!

Program: ...demCpp\windows\TBSKmodemCpp\x64\Debug\ConsoleApplication1.exe
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 904

Expression: _CrtIsValidHeapPointer(block)

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

回避方法

shared_ptrにすると正常に動作します。

shared_ptr<Base> CreatePointer()
{
	auto a = make_shared<Extends>();
	return a;
}

virtualを取り除いても正常に動作します。

class Extends : public Base{};

MSVC固有の問題なのかの切り分けまではしていません。