Ошибка при использовании абстрактного класса std::make_shared

Я собираюсь опустить довольно много кода, потому что это довольно большие объекты, и мой вопрос на самом деле касается только операции std::make_shared . У меня есть объект в пространстве имен SYNC, который называется D3D11Shader. Это имеет статическую функцию под названием,

SYNC::D3D11Shader * SYNC::D3D11Shader::CreateInstance(const std::string & s)

который возьмет строковый индекс и вернет указатель на экземпляр шейдера, производного от SYNC::D3D11Shader. В какой-то момент я начал использовать умные указатели для автоматизации их удаления в векторе, который содержал все эти шейдеры. Тем не менее, когда я иду, чтобы сделать это,

 std::shared_ptr<SYNC::D3D11Shader> shaderPtr;
 // ... verification of index and other initialization happens here
 // so i am unable to initialize it in it's constructor
 shaderPtr = std::make_shared<SYNC::D3D11Shader>(SYNC::D3D11Shader::CreateShader(shaderName));

ошибки компилятора, говорящие о том, что я пытаюсь создать экземпляр D3D11Shader в этой строке, который является абстрактным классом. Я думал, что все, что сделал make_shared - это вернул экземпляр std::shared_ptr. Функция CreateInstance никогда не пытается создать экземпляр этого класса, только объекты, которые его производят и реализуют. Я не получал эту ошибку до использования этой функции и умных указателей. Кто-нибудь знает, что здесь происходит?

2 ответа

Решение

Если вы не можете использовать конструктор shared_ptr, используйте его reset Функция-член, чтобы дать ему право собственности на новый объект:

std::shared_ptr<SYNC::D3D11Shader> shaderPtr;
shaderPtr.reset(SYNC::D3D11Shader::CreateShader(shaderName));

Причина make_shared<T> не подходит для этой ситуации, потому что он создает новый T, передавая свои аргументы своему конструктору. Однако вы уже сконструировали объект, поэтому вам просто нужно передать право владения вашим общим указателем.

Я настоятельно рекомендую не возвращать необработанный указатель из CreateShader хоть. Вы полагаетесь на абонента CreateShader знать, чтобы обернуть это в умный указатель или вызов delete в теме. Вам лучше вернуть unique_ptr передать право собственности клиенту, а затем они могут сделать shared_ptr из этого, если им нравится. Смотрите следующее:

std::unique_ptr<SYNC::D3D11Shader> uniquePtr(SYNC::D3D11Shader::CreateShader(shaderName));
// If you want a shared_ptr:
std::shared_ptr<SYNC::D3D11Shader> sharedPtr(std::move(uniquePtr));

Или просто:

std::shared_ptr<SYNC::D3D11Shader> sharedPtr = SYNC::D3D11Shader::CreateShader(shaderName);

Если вы собираетесь использовать умные указатели, используйте их.:)

Достаточно просто:

shaderPtr.reset(SYNC::D3D11Shader::CreateShader(shaderName));

Вы можете увидеть различные варианты reset функция-член здесь.

Другие вопросы по тегам