#c #pointers #templates #destructor #dynamic-memory-allocation
Вопрос:
Почему это не может сработать. Есть ли какой-нибудь способ сделать это? Я не хочу создавать отдельную функцию для указателей
#include <iostream>
using namespace std;
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
~temp()
{
if(is_pointer<T>::value)
{
delete val;
}
}
};
int main()
{
string * n = new string("cat");
temp<string*>object(n);//ok
temp<string>object2("dog"); //compliation error: type 'class std::cxx11::basic_string' argument given to 'delete', expected pointer. --- (but there is if statement!!!!)
//i dont want delete in main
return 0;
}
Для компиляции я использую g 6.3.0
Может ли кто-нибудь помочь? Может быть, мне нужно отделить декларацию от определения?
Комментарии:
1. Пожалуйста, предоставьте дополнительную информацию, такую как конфигурация, компилятор, версия C , сведения об ошибках и фактический вопрос.
2. Технически ваш
temp
класс не является владельцем указателя или данных, на которые он указывает. Поэтому он не должен пытатьсяdelete
это сделать.3. Вечное основное правило таково:
delete
с чем ты творилnew
, иdelete[]
с чем ты творилnew[]
. Если вы передадите указатель,temp
вы все равно не сможете быть уверены, что он может бытьdelete
d, не вызывая неопределенного поведения. Представь, что я использую твоеtemp<int*>
дляint i; temp<int*> tI(amp;i);
…4.
new string("cat")
это запах кода, не удаление егоmain
просто делает его немного хуже. Можете ли вы объяснить, в чем заключается цель? Почему нетtemp<string>
? или если вы настаиваете на динамическом распределенииtemp< std::unique_ptr<std::string>>
?5. С C 17
if constexpr (is_pointer<T>::value)
позволит это скомпилировать (хотя у него все равно будут проблемы, упомянутые другими комментаторами)
Ответ №1:
Проблема, с которой вы столкнулись, заключается в том, что ветвь an if
всегда должна быть синтаксически корректной, даже если она никогда не используется.
Вы могли бы сделать это с if constexpr
помощью , что является «временем компиляции, если»
~temp()
{
if constexpr(is_pointer<T>::value)
{
delete val;
}
}
Однако это небезопасно.
Откуда вы знаете, что указатель , на который был передан temp<T*>
, был создан, new
а не new[]
malloc
, или путем получения адреса объекта, который не был динамически выделен?
Вместо того, чтобы предполагать, что указатели должны быть удалены, вам следует избегать необходимости знать, какие указатели следует удалить
#include <string>
#include <memory>
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
// n.b. no need to define destructor
};
int main()
{
std::string str("cat");
temp<std::string*> object(amp;str);//ok
temp<std::string> object2("dog"); // also ok
std::unique_ptr<std::string> str2 = std::make_unique<std::string>("mouse");
temp<std::string *> object3(str2.get()); // ok so long as str2 outlives object3
std::shared_ptr<std::string> str3 = std::make_shared<std::string>("rabbit");
temp<std::shared_ptr<std::string>> object4(str3); // also ok
return 0;
}
Комментарии:
1. вы предлагаете
delete
вообще не входить в деструктор? Не уверен, что я понимаю ответ, потому что с вашим исправлениемconstexpr
строкиtemp<std::string*> object(amp;str);
не «ок».2. @463035818_is_not_a_number действительно