#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
не является кандидатом для вызова. Я не уверен, что есть способ заставить этот оператор работать.