Защо предупреждението C4265 Visual C++ (виртуална членска функция и без виртуален деструктор) е изключено по подразбиране?

Visual C++ може да излъчва C4265 предупреждение, когато класът има поне една виртуална членска функция и няма виртуален деструктор.

Очевидно предупреждението е там, за да открие случаи, когато обект от производен клас е deleted през указател към базовия клас и няма виртуален деструктор в базовия клас. Такава ситуация води до неопределено поведение. Между другото току-що намерих пример за тази ситуация в доста огромна кодова база именно чрез активиране на C4265 във Visual C++.

И това предупреждение е изключено по подразбиране.

Защо? Какво ще стане, ако го активирам и добавя виртуален деструктор към всеки клас, където се излъчва предупреждението?


person sharptooth    schedule 08.11.2011    source източник


Отговори (4)


В връзката за документацията за това предупреждение обяснява мотивите на Microsoft. If a warning is off by default, most users would not want to see it.

person Hans Olsson    schedule 08.11.2011

Предполагам, че понякога не се нуждаете от виртуален деструктор, дори ако имате виртуални функции (и следователно помислете за наследяване от него).

Имате нужда от виртуален деструктор, ако разпределите памет в производен клас и трябва да я освободите при унищожаване на обект, но това не винаги е така.

Виртуален деструктор също така означава, че трябва да имплементирате конструктор за копиране и оператор за присвояване (правилото на трите), които също не са необходими, ако членовете на вашия клас са просто типове POD.

И така, за да обобщим: ще получите това предупреждение дори за класове, където не се нуждаете от виртуалния деструктор, така че защо ви е?

person Luchian Grigore    schedule 08.11.2011
comment
Не мисля, че правилото на трите важи по този начин. Празен виртуален деструктор е достатъчен за полиморфно изтриване. Е същият деструктор, който вече имате (осигурен от компилатора), само virtual. - person K-ballo; 08.11.2011

Мисля, че много предупреждения могат да бъдат сред тези, които използват модела Mixin класове.

WikiPedia: В обектно-ориентираните езици за програмиране миксинът е клас, който предоставя определена функционалност, която да бъде наследена или просто повторно използвана от подклас, като същевременно не е предназначена за инстанциране (генериране на обекти от този клас). Миксините са синоним на абстрактни базови класове. Наследяването от mixin не е форма на специализация, а е по-скоро средство за събиране на функционалност. Клас или обект може да "наследи" повечето или цялата си функционалност от един или повече миксини, следователно миксините могат да се разглеждат като механизъм за множествено наследяване.

Пример:

Смесен клас

template <typename T> struct AddNoEq {
  virtual bool operator==(const T &cmp) const = 0;
  bool operator!=(const T &cmp) const {
    return !static_cast<const T*>(this)->operator== (cmp);
  }
};

Използвайте:

struct Complex : public AddNoEq<Complex> {
  Complex(int re, int im): re_(re), im_(im) { }

  virtual bool operator==(const Complex& cmp) const {
      return cmp.re_ == this->re_ && cmp.im_ == this->im_;
  }
  // ...
private:
  int re_, im_;
};

int main()
{
  Complex a(1, 2), b(2, 3);

    if (a != b)
      std::cout << "OK!" << std::endl;

    return 0;
}
person Community    schedule 21.01.2012

Понякога Microsoft предупреждава за „отхвърлени функции“, които не са маркирани като такива от комитета по спецификациите, или за определени „добри или лоши практики“.

Наличието на невиртуален деструктор в обект, който има виртуални методи, е потенциален риск, ако този обект е проектиран да напусне полиморфна ООП среда (където delete pObject трябва правилно също така delete pDerived, дори ако се гледа с pObject). Но това е само една от парадигмите за поддръжка на C++... следователно такова предупреждение може да е безсмислено:

Също така p->dosomething() не извиква Derived::dosomething, ако dosomething не е виртуален, но не се генерира предупреждение за това.

За мен delete p преструването, че P::~P() води до извикване на D::~D(), не е специален случай и не трябва да заслужава предупреждение.

Но - за съжаление - ООП беше първата парадигма, която C++ първоначално поддържаше и парадигмата, за която се позовават повечето програмисти и циркулиращи книги и учители, така че те внедриха най-добрата практика „не извличай, ако деструкторът не е виртуален“, за съжаление докладвано също от Скот Майерс в неговия „Ефективен C++“, като по този начин го прави „популярен“ и непрекъснато се споменава също, ако няма техническа причина да продължи да съществува.

Днес е безсмислен смисъл като повечето от „не правете това, не правете онова“ (включително известното „goto се счита за вредно“ от Dijkstra, което постави много нов акцент върху структурираното програмиране, но също така и много нелепи начини за завъртете се, за да го избегнете. Ха ... Microsoft все още няма предупреждение за използването на goto ... Може би Майерс е по-влиятелен от Джикстра??)

Единствената добра практика е „не правете НИЩО, ако не знаете какво правите!“. Нищо не забранява да се приеме предложение, но „най-добрата практика“ не е „винаги добра практика“ (в противен случай няма да е „най-добра“: просто ще бъде „само“) и компилаторът (като формален инструмент) не трябва да предупреждава за субективни чувства.

person Emilio Garavaglia    schedule 08.11.2011