Избегать `delete []` принятия неявного преобразования указателя?

#c #operator-overloading #delete-operator #conversion-operator

#c #перегрузка оператора #оператор удаления #преобразование-оператор

Вопрос:

У меня есть класс с неявным оператором преобразования в указатель. Освобождение этого указателя недопустимо. Могу ли я предотвратить преобразование в указатель при использовании с delete[] оператором? Я хотел бы получить ошибку во время компиляции. Для free функции я могу удалить перегрузку, которая принимает класс в качестве аргумента.

 void foobar(double*){}

struct A {
  // Please pretend I have a good reason for doing this.
  operator double*() const { return nullptr; }
};

void free(Aamp;) = delete;

int main(){
  A a;
  
  // Just works TM
  foobar(a);

  // This compiles :(
  delete[] a;
  // This does not :)
  //free(a);
  return 0;
}
  

Я думаю, что для желаемого эффекта потребуется что-то умное.


Пример использования неявного преобразования: скажем A , реализует ограниченный массив. Преобразование приводит A к почти полной замене пары alloc / dealloc. Шаблоны и итераторы, требующие явного преобразования. В противном случае сайты вызовов c-подобных функций остаются неизменными.

Комментарии:

1. Хотя std::free(a) будет компилироваться даже с вашим кодом

2. Вам нужно, чтобы оператор преобразования был неявным? Пометка решила explicit бы проблему.

3. Вы могли бы добавить a operator void*() const { return nullptr; } , чтобы сделать ситуацию неоднозначной.

4. @Eljay Это, кажется, ответ! При ограниченном использовании до сих пор я также не вижу других неудобных двусмысленностей. Хотя некоторые все еще могут быть. Побочный эффект -Wdelete-incomplete существующего, а не просто ошибка.

5. Вам действительно нужен оператор преобразования , а не более простой метод? double* A::toDoublePtr() const { return ...; }

Ответ №1:

В качестве обходного пути вы можете предотвратить преобразование в указатель при использовании с delete[] оператором, сделав преобразование неоднозначным.

Однако, в зависимости от ситуации с остальной частью кода, это может вызвать нежелательную двусмысленность для желаемых вариантов использования.

 struct A {
  operator double*() const { return nullptr; }
  operator void*() const { return nullptr; }
};
  

Ответ №2:

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

 void foobar(double*){}

class A {
  // Please pretend I have a good reason for doing this.
  public : 
  operator double*() const { return nullptr; }
  template<typename type>
  void operator delete[] (void*, type size); 
};

template<typename type>
void free(void*);

template<>
void free<A>(void*) = delete;

int main(){
  A a;
  
  // Just works TM
  foobar(a);

  // Now this will not compile to ! :(
  delete[] a;
  // This does not :)
  //free(a);
  return 0;
}
  

Комментарии:

1. Это не сработало. Без delete[] a; этого я все равно получаю «ошибка: ожидаемый неквалифицированный идентификатор перед ‘delete’» @ void delete[] ( … Пробовал компиляцию с g -std=c 17 foo.cpp

2. На самом деле, я ошибся, поэтому я изменил свой ответ, и это, наконец, работает

3.Обновленная версия компилируется даже с. delete[] a; Определенный delete не является кандидатом для вызова. Я не уверен, что есть способ заставить этот оператор работать.