Остановка неявного приведения к оператору delete - PullRequest
1 голос
/ 26 января 2010

Мой класс String предоставляет перегрузку char * оператора, позволяющую передавать строку в функции C.

К сожалению, мой коллега случайно обнаружил ошибку.

У него фактически был следующий код.

StringT str;
// Some code.
delete str;

Есть ли способ предотвратить приведение delete к строковому объекту к символу *, чтобы предотвратить появление таких ошибок в будущем? std::string обходит эту проблему, не предоставляя перегрузку оператора char, но в идеале я хотел бы сохранить перегрузку, но предотвратить удаление этой операции.

Ответы [ 5 ]

8 голосов
/ 26 января 2010

Да. Обеспечьте ДВА неявных приведения, объявив (но не определяя!) operator char const volatile*. Когда вы передаете ваш StringT в строковую функцию C, разрешение перегрузки все равно выберет ваш исходный operator char const* (точное соответствие). Но delete str; теперь становится двусмысленным.

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

5 голосов
/ 26 января 2010

Есть ли какой-либо способ запретить delete приводить строковый объект к символу * ...?

Да: уклоняться от неявных операторов приведения. Это проповедовалось уже как минимум десять лет. Верьте в это, и вы будете жить счастливее.

4 голосов
/ 26 января 2010

Верьте или нет, есть причина, по которой std :: string не обеспечивает неявное преобразование, функция c_str () не была создана просто для того, чтобы раздражать вас. Обеспечьте неявное обращение, и вы откроете себя миру неопределенности и боли.

0 голосов
/ 26 января 2010
struct Dummy {};
class StringT {
public:
    // ........
    operator char*() { /*...*/ }
    operator const char*() const { /*...*/ }

    operator const Dummy* () const { return 0; }
    operator Dummy* () { return 0; }
};

/// ...
void g(const char * ) { /*...*/ }

int main() {

    StringT str;
    g(str); // OK
    delete str; //error C2440: 'delete' : cannot convert from 'StringT' to 'void *'
    return 0;
}
0 голосов
/ 26 января 2010

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

Перефразируя ваш вопрос:

Как мне удержать людей от использования моего огнестрельного оружия, чтобы выстрелить себе в ногу?

Вы не можете.Я не согласен с мнением @ sbi и скажу, что ваша перегрузка в порядке .Если это вызывает проблемы в чьем-то коде, то это потому, что кто-то не знает C ++ и не должен его кодировать.

У вас есть большие проблемы, о которых нужно беспокоиться, чем о том, хорошо ли кто-то не понимает язык.Достаточно, чтобы не знать, что delete вещи, которые не являются указателями, могут злоупотреблять вашим классом.

Предостережение: Я относительно новичок в C ++ и не видел ужасов некоторых более вихревых ветеранов.Возможно, что образец особенно плохой двусмысленности мог убедить меня в моих злых путях.Это, однако, не так.

...