[achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 27.05.20 16:13
Оценка: 26 (4)
Чуть было не наступил на грабли

Есть код вида

#include <iostream>
#include <vector>

class TVAR
{
 public:
  TVAR(bool               /*v*/) {std::cout << "TVAR: bool\n";}
  TVAR(const char*        /*v*/) {std::cout << "TVAR: const char*\n";}
  TVAR(const std::string& /*v*/) {std::cout << "TVAR: std::string\n";}
};

int main()
{
 std::vector<TVAR> vec;

 vec.push_back("1234");
}


Работает как ожидается — push_back вызывает конструктор TVAR(const char*).

Решил его "улучшить" и заменить конструкторы TVAR(const char*) и TVAR(const std::string&) на унифицированный конструктор TVAR(const std::string_view&).

#include <iostream>
#include <vector>

class TVAR
{
 public:
  TVAR(bool               /*v*/) {std::cout << "TVAR: bool\n";}

  TVAR(const std::string_view& /*v*/) {std::cout << "TVAR: std::string_view\n";}
};

int main()
{
 std::vector<TVAR> vec;

 vec.push_back("1234");
}


И огрёб, потому что начал вызываться конструктор TVAR(bool)

Реально стрёмно.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: [achtung] cast указателя к bool
От: Alexander G Украина  
Дата: 28.05.20 05:14
Оценка: 15 (3)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Реально стрёмно.


Классика, но да, с этим string_view примером новый повод наступить.

Наткнулся на похожее, когда NULL заменить на nullptr, начинает вызываться строковая версия.
(При этом, так получалось, что в месте, где NULL, нужна была именно булочная перегрузка)

Примерно так реконструировать можно для этого примера:
#include <iostream>
#include <vector>

class TVAR
{
public:
    explicit TVAR(bool               /*v*/) { std::cout << "TVAR: bool\n"; }
    explicit TVAR(const std::string_view& /*v*/) { std::cout << "TVAR: std::string_view\n"; }
};

int main()
{
    std::vector<TVAR> vec;

    vec.emplace_back(NULL); // bool
    vec.emplace_back(nullptr); // string_view
}
Русский военный корабль идёт ко дну!
Re[2]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.05.20 06:43
Оценка: 6 (1) +1
Здравствуйте, Alexander G, Вы писали:

КД>>Реально стрёмно.


AG>Классика, но да, с этим string_view примером новый повод наступить.


AG>Наткнулся на похожее, когда NULL заменить на nullptr, начинает вызываться строковая версия.

AG>(При этом, так получалось, что в месте, где NULL, нужна была именно булочная перегрузка)

Я пришел к выводу, что конструкции вида "TVAR(const char*)" и "operator = (const char*)" не нужно удалять.

Вообще, как по мне, их лучше явно запретить (=delete).
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: [achtung] cast указателя к bool
От: Alexander G Украина  
Дата: 28.05.20 07:13
Оценка: 8 (1) :)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Вообще, как по мне, их лучше явно запретить (=delete).


И писать всегда std::string_view("Literal") или std::string_view{} для пустой строки?

Кстати, я бы тогда хелперы предложил, заодно минус лишний strlen:

template<std::size_t Size>
std::string_view string_from_literal(const char (&data)[Size])
{
  return std::string_view(data, data+Size);
}

inline constexpr null_string = std::string_view{};
Русский военный корабль идёт ко дну!
Re[4]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.05.20 07:50
Оценка: 7 (1) +1
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>>Вообще, как по мне, их лучше явно запретить (=delete).


AG>И писать всегда std::string_view("Literal") или std::string_view{} для пустой строки?


В моих трех тыщах файлов основного проекта, вылезло 21 место, где вызывается конструктор/оператор_присваивания для const char*.

Сижу, думаю

  AG>Кстати, я бы тогда хелперы предложил, заодно минус лишний strlen:
template<std::size_t Size>
std::string_view string_from_literal(const char (&data)[Size])
{
  return std::string_view(data, data+Size);
}

inline constexpr null_string = std::string_view{};

+5

UPD. А оно точно будет работать как ожидается? Что-то у меня сомнения насчет того, что в Size не будет включен терминальный нуль. Надо проверить
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 28.05.2020 8:24 DDDX . Предыдущая версия . Еще …
Отредактировано 28.05.2020 7:53 DDDX . Предыдущая версия .
Re[5]: [achtung] cast указателя к bool
От: Alexander G Украина  
Дата: 28.05.20 07:57
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>UPD. А оно точно будет работать как ожидается? Что-то у меня сомнения насчет того, что в Size не будет включен терминальный нуль. Надо проверить


Непременно будет, и всегда. ну кроме "литералов" вроде char c[] = {'h','e','l','l',o'};, которые просто не использовать с такой функцией.
Итак, дубль два:

template<std::size_t Size>
std::string_view string_from_literal(const char (&data)[Size], const bool trim_trailing_null = true)
{
  return std::string_view(data, data+Size-trim_trailing_null);
}
Русский военный корабль идёт ко дну!
Re[5]: Стоп, хелперы уже написаны до нас
От: Alexander G Украина  
Дата: 28.05.20 08:05
Оценка: 21 (4) +1
Стоп, хелперы уже написаны до нас

using namespace std::literals::string_view_literals;

"Hello"sv;

""sv;
Русский военный корабль идёт ко дну!
Отредактировано 28.05.2020 8:06 Alexander G . Предыдущая версия .
Re[6]: Стоп, хелперы уже написаны до нас
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.05.20 08:17
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Стоп, хелперы уже написаны до нас


AG>
AG>using namespace std::literals::string_view_literals;

AG>"Hello"sv;

AG>""sv;
AG>


Божественно.

Еще один весомый довод в пользу переезда на C++17 — я пока на низком старте
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: [achtung] cast указателя к bool
От: Alexander G Украина  
Дата: 28.05.20 08:25
Оценка: 6 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Вообще, как по мне, их лучше явно запретить (=delete).


Я бы задепрекейтил:

#include <iostream>
#include <vector>

class TVAR
{
public:
    [[deprecated("No, use \"literal\"sv for instead of \"literal\". For non-literals construct string_view explicitly")]]
    TVAR(const char*        /*v*/) { std::cout << "TVAR: const char*\n"; }
    TVAR(const std::string_view& /*v*/) { std::cout << "TVAR: std::string\n"; }

};

int main()
{
    using namespace std::string_view_literals;
    std::vector<TVAR> vec;
    vec.push_back("1234"); // warning
    vec.push_back("1234"sv); // no warning
}
Русский военный корабль идёт ко дну!
Re[4]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.05.20 08:29
Оценка:
Здравствуйте, Alexander G, Вы писали:

КД>>Вообще, как по мне, их лучше явно запретить (=delete).


AG>Я бы задепрекейтил:


Я вечером обязательно за тебя стаканчик выпью.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: [achtung] cast указателя к bool
От: rg45 СССР  
Дата: 29.05.20 11:51
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>И огрёб, потому что начал вызываться конструктор TVAR(bool)

КД>Реально стрёмно.

Так может, имеет смысл объявить этот конструктор как explicit?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 29.05.20 16:12
Оценка:
Здравствуйте, rg45, Вы писали:

КД>>И огрёб, потому что начал вызываться конструктор TVAR(bool)

КД>>Реально стрёмно.

R>Так может, имеет смысл объявить этот конструктор как explicit?


Не думаю, чтобы это сильно помогло/защитило. А хуже точно сделает.

Я кстати, почти наступил на эти грабли (в реальном коде) когда юзал emplace_back. То есть, explicit был бы побоку.

В целом, это аналог VARIANT-а.

Тут куча конструкторов на разный вкус и цвет. И все могут вызываться неявно.

Явный конструктор для bool всю малину испортит
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 29.05.2020 16:26 DDDX . Предыдущая версия .
Re[3]: [achtung] cast указателя к bool
От: rg45 СССР  
Дата: 30.05.20 08:28
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>Не думаю, чтобы это сильно помогло/защитило. А хуже точно сделает.

КД>Я кстати, почти наступил на эти грабли (в реальном коде) когда юзал emplace_back. То есть, explicit был бы побоку.
КД>В целом, это аналог VARIANT-а.
КД>Тут куча конструкторов на разный вкус и цвет. И все могут вызываться неявно.
КД>Явный конструктор для bool всю малину испортит

Да, грабли тут в том, что даже при явном вызове конструкторов вызывается не тот конструктор, который ожидается. Поэтому explicit погоды не делает.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: [achtung] cast указателя к bool
От: ArtDenis Россия  
Дата: 30.05.20 09:05
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>...

КД>Реально стрёмно.

А почему [achtung]? Это же классика.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.05.20 09:31
Оценка:
Здравствуйте, ArtDenis, Вы писали:

КД>>...

КД>>Реально стрёмно.

AD>А почему [achtung]? Это же классика.


Потому что тупеешь и всю эту классику в башке удерживать уже не хочется — в ней место под еду уже начало не хватать

Надо было для конструктора с (const char*) написать соответствующий каммент.

---
Начал добавлять ассеры, которые контролируют и вылавливают подобные вещи.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: [achtung] cast указателя к bool
От: Zhendos  
Дата: 30.05.20 19:10
Оценка: 16 (1)
Здравствуйте, Alexander G, Вы писали:


AG>И писать всегда std::string_view("Literal") или std::string_view{} для пустой строки?


AG>Кстати, я бы тогда хелперы предложил, заодно минус лишний strlen:


Так clang/gcc давно считают strlen в compile time для строковых литералов,
откуда лишний strlen?
Re[5]: [achtung] cast указателя к bool
От: Alexander G Украина  
Дата: 31.05.20 12:40
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Так clang/gcc давно считают strlen в compile time для строковых литералов,

Z>откуда лишний strlen?

Однако, да. Привык, что MSVC не считает. Но уже считает и для string_view, и для string (вызывает __builtin_strlen).

https://godbolt.org/z/gMQZdS
Русский военный корабль идёт ко дну!
Отредактировано 31.05.2020 12:44 Alexander G . Предыдущая версия .
Re[4]: [achtung] cast указателя к bool
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 02.06.20 07:15
Оценка:
Здравствуйте, rg45, Вы писали:

КД>>Не думаю, чтобы это сильно помогло/защитило. А хуже точно сделает.

КД>>Я кстати, почти наступил на эти грабли (в реальном коде) когда юзал emplace_back. То есть, explicit был бы побоку.
КД>>В целом, это аналог VARIANT-а.
КД>>Тут куча конструкторов на разный вкус и цвет. И все могут вызываться неявно.
КД>>Явный конструктор для bool всю малину испортит

R>Да, грабли тут в том, что даже при явном вызове конструкторов вызывается не тот конструктор, который ожидается. Поэтому explicit погоды не делает.


Обнаружил тут
Автор: YuriV
Дата: 23.05.20
ссылку на документ.

После прочтения которого, подумалось — "надо бы эту хрень с неявным преобразованием указателя к bool изничтожить как класс"

Понятное дело, будет очень больно.

Но, думаю, это вопрос времени — лет через 20, запретят.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 02.06.2020 7:17 DDDX . Предыдущая версия .
Re[5]: [achtung] cast указателя к bool
От: CEMb  
Дата: 30.06.20 07:14
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Обнаружил тут
Автор: YuriV
Дата: 23.05.20
ссылку на документ.


КД>После прочтения которого, подумалось — "надо бы эту хрень с неявным преобразованием указателя к bool изничтожить как класс"


Это же наследие C?

КД>Понятное дело, будет очень больно.


Я уже давно стараюсь в условиях писать == nullptr / != nullptr с указателями.

КД>Но, думаю, это вопрос времени — лет через 20, запретят.


Можно сделать свой условный оператор, который будет ругаться на момент компиляции, если в него поступил не bool?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.