Деструктор для указателя и не указателя

#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 действительно