All streams
Search
Write a publication
Pull to refresh
215
0
gribozavr @gribozavr

Пользователь

Send message
Нельзя делать #define NULL whatever в пользовательском коде.
Это нельзя делать. UB.
И? Вы же написали temp!=0, а не temp!=1-1.
Это UB в момент вызова.
При чём тут компилятор? Вызывать функции-члены если у вас нет живого объекта — undefined behavior в момент вызова.
> if(this != NULL){

Epic. Так не бывает.
Я не вижу где вы здесь использовали нетривиальный integral constant expression, равный нулю, в качестве null pointer constant.
Это потому что в компиляторах именно из-за этого примера есть костыль, который не совместим с C++03. В C++03 нужно
#define NULL 0


Однако в GCC и Clang:
#define NULL __null


И дальше компилятор разбирается по правилам, которых нет в языке.
> Конечно нет! И потому не согласен с тем, что NULL можно заменять в коде 0.

Но NULL проблемы не решает, а словить пару часов интереснейшей отладки overload resolution можно элементарно. Если же там был бы написан ноль, было бы всё понятно.

И вообще, это сегодня неактуально. nullptr.
Да, пример использования в студию.
То есть вы считаете нормальным, что f(2*24 — 42) компилируется, а f(2*42-43) — нет?
Вы, кажется, не предвидели всей полноты последствий:
$ cat zz.cc
#include <iostream>
#include <stddef.h>

void f(int *x) { std::cout << "int *x" << std::endl; }
void f(int x)  { std::cout << "int x" << std::endl; }

int main() {
  f(0);
}


Overload resolution выбирает f(int) для NULL (если #define NULL 0), точно также как и для 0.
См. ответ выше. Проблема в неинтуитивном определении null pointer constant в C++03.
А как же тогда работает код у ваших студентов? Дело в том, что integral constant expression, равный нулю, является null pointer constant и может быть преобразован к T*.

void f(int *x);

void g() {
  f(2 * 21 - 42); // OK
}
> Срабатывает приведение типов — NULL -> int(0).

Нет такого неявного приведения типов в C++: T* не приводится неявно к int.

void f(int x);

void g() {
  int *p = 0;
  f(p); // compile error
}
> При простом переносе определения геттеров в файлы имплементации, выключится существенно меньше inline-ов. Поэтому тест не совсем корректен.

Не согласен со словом «существенно». Зависит от приложения.

> Фактически, я бы сказал, что по умолчанию вы делаете все функции классов невстраиваемыми, если нет явной причины сделать их встраиваемыми.

А вот с этим я согласен.
Дело в том, что NULL в C++ должен быть определён как
#define NULL 0


Определять NULL как (void *)0 нельзя. Поэтому следующий код является корректным:
f(int x);

void g() {
  f(NULL);
}


Я согласен что это неинтуитивно. Что именно использовать в C++03 — NULL или 0 — определяется стилем кодирования в каждом проекте, так как саму проблему с null pointer constant в C++03 не решает.
> Да, но вы отключили встраивание глобально

Да. Что вы дальше хотели сказать я так и не понял. (Обычный R+A компилировался без LTO, если вы это имели ввиду.)

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

Основные — да. Но не все. Кроме того, мы же обсуждаем «правило» что инлайн функции в классах определять «НЕЛЬЗЯ». Поэтому считаю тест корректным.
> Все это не имеет прямого отношения к определению функции в заголовочном файле.

КО: заголовочный файл становится частью многих единиц трансляции.

> С другой стороны, ваш тест не показывает, сколько процентов кода тормозит.

Без инлайнинга код начинает тормозить везде равномерно.
0 — C++98, C++03. В C++11 тоже можно 0, но лучше nullptr.

Information

Rating
Does not participate
Location
Украина
Registered
Activity