Об этом и речь. Скажем, если разработчик не понимает, что делает, то возможна такая ситуация: разработчик написал неверный код (с владеющим указателем или без), статический анализатор ему на это указал, разработчик не пытается понять, в чем на самом деле проблема, и не ищет, как написать правильный код, а вместо этого пытается сделать так, чтобы анализатор заткнулся. Технические средства не отменяют необходимость думать.
Да, вы правы, во многих случаях нужно просто использовать vector. Один из случаев, когда vector неудобен, — выделение памяти для последующей передачи ее во владение сторонней библиотеке вроде zlib.
В общем, справедливо. Но написать «произойдет ужос, ужос, ваша программа превратит компьютер в черную дыру» — тоже не вариант. Пришлось рассмотреть один пример. Там, кстати, говорится, что это одна из реализаций.
Это классика. auto_ptr в деструкторе вызовет delete без скобок, это точно та же ситуация, что в двух примерах в посте. «Это нехорошо» — немного неудачная характеристика. И кстати, вы пытаетесь «объяснить», что произойдет.
Да, действительно, владеющие указатели и RAII вообще — отличная штука. Только ими нужно пользоваться не «потому что нужно», а с пониманием, какие проблемы они решают. Пост как раз об одной из таких проблем.
Кстати, вот пример, когда владеющий указатель использован неверно и это привело к дефекту в программе.
Lingvo Intranet Server не предусматривает установку на Linux-, Unix- и другие никсовые сервера. Но есть Lingvo Web Server. Этот продукт можно использовать независимо от платформы, в том числе и Linux.
ABBYY LingvoServer предусматривает ежегодные платежи за пользование словарем. В зависимости от того, какая версия у вас стоит и сколько лицензий у вас уже есть, можно рассматривать вариант с предоставлением скидки при переходе на LingvoServer. Пожалуйста, обратитесь в офис ABBYY за консультацией — (495) 783-3700.
Камера на iPod Touch не позволяет использовать автофокус и предназначена для съемки видео. В дальнейшем, когда Apple улучшит камеру в iPod Touch, мы ее безо всякого сомнения поддержим.
видите, даже InterlockedDecrement() используется. Но здесь возможна ситуация, когда метод будет вызван двумя потоками одновременно, первый поток получит от InterlockedDecrement() единицу, второй — ноль, и второй поток выполнит delete раньше, чем первый прочитает поле класса, возникнет неопределенное поведение.
Из того, что что-то написано в «правильной книжке», не следует, что это правильно и многим очевидно. Нужно не только внимательно читать книги; думать и подвергать свои знания сомнению тоже не вредно.
Приведенная вами реализация QueryInterface(), кстати, рассчитывает на то, что вызывающая сторона сначала запишет нулевой указатель в *ppv, хотя, во-первых, такое требование нигде не указывается, и во-вторых, вызывающая сторона может из-за ошибки забыть это сделать даже если собиралась.
Теперь, если вызывающая сторона передаст адрес указателя, в котором хранится ненулевое значение и, например, __uuidof(IDraw), в *ppv останется то ненулевое значение и вызов AddRef() приведет в неопределенному поведению.
Каждый сам решает, сколько паранойи ему нужно в его коде, не правда ли? Решение использовать шаблонную функцию было принято сознательно — в первую очередь для того, чтобы иметь предельно подробную выдачу в журнал. Можно ли его считать изобретением велосипеда просто потому, что заново написан код извлечения интерфейса? Очень может быть.
Если вы используете COM_INTERFACE_ENTRY_FUNC, то никто не проверит, что вы туда передали, соответствие идентификатора и функции будет на вашей совести.
Когда ваш объект используется из процесса, о работе которого вы вообще ничего не знаете, чем больше в вашем коде паранойи, тем быстрее отладка. Чем принципиально хуже шаблонная функция, которая проверяет все параметры и либо сама извлекает интерфейс и пишет в журнал, что она его извлекла, либо пишет ясное сообщение об ошибке и возвращает код, обозначающий ошибку?
Кстати, вот пример, когда владеющий указатель использован неверно и это привело к дефекту в программе.
Вот пример реализации IUnknown::Release() из другой «правильной книжки»:
ULONG __stdcall CA::Release() { if (::InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return m_cRef; }видите, даже InterlockedDecrement() используется. Но здесь возможна ситуация, когда метод будет вызван двумя потоками одновременно, первый поток получит от InterlockedDecrement() единицу, второй — ноль, и второй поток выполнит delete раньше, чем первый прочитает поле класса, возникнет неопределенное поведение.
Из того, что что-то написано в «правильной книжке», не следует, что это правильно и многим очевидно. Нужно не только внимательно читать книги; думать и подвергать свои знания сомнению тоже не вредно.
Теперь, если вызывающая сторона передаст адрес указателя, в котором хранится ненулевое значение и, например, __uuidof(IDraw), в *ppv останется то ненулевое значение и вызов AddRef() приведет в неопределенному поведению.