LINUX.ORG.RU

Базовые типы

 ,


0

2

Пусть есть

int a;
double b;

Как лучше делать?

a = (int)b;
или
a = static_cast<int>(b);
?

Другой вопрос с методами\функциями:

void foo(const int & a);
void foo(const double & b);
или
void foo(int a);
void foo(double b);
?



Последнее исправление: hired777 (всего исправлений: 1)

Ответ на: комментарий от hired777

потому, что (type) это С-style каст

потому, что выигрыша от передачи константной ссылки на скаляр нет

x0r ★★★★★
()
Ответ на: комментарий от Kiborg

Если структура - лучше по константной ссылке.

com
()
Ответ на: комментарий от x0r

потому, что выигрыша от передачи константной ссылки на скаляр нет

Ну, а если я постоянно пишу

void foo(const int & a);
и говорю «я так привык» - сильно бить по рукам будут?)

hired777
() автор топика
Ответ на: комментарий от Kiborg

А если «a» - это какая-нибудь структура?

Лучше константная ссылка - так не будет копирования.

hired777
() автор топика
Ответ на: комментарий от x0r

Ага. Вопрос был скорее риторический, чтобы исключить возможность того, что ТС «по аналогии» решит, что передавать по значению всегда лучше.

Kiborg ★★★
()
Ответ на: комментарий от x0r

Можно предположить, что если возможен вариант с foo (const int & a), то значение 'a' не меняется, в таком случае лучше таки передавать по значению, но константно, т. е. foo (const int a)

tff
()
Ответ на: комментарий от AIv

И не забыть каждый темплейт вида

template <class T>
void foo(const T &bar
{
    // ...
}
руками проспециализировать для всех примитивных типов. А то бессмыслица и потеря эффективности же.

ilammy ★★★
()
Ответ на: комментарий от AIv

у арифметики жирнее рантайм, чем у каста. хотя для float/double лучше проверить явно.

x0r ★★★★★
()
Ответ на: комментарий от tff

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

x0r ★★★★★
()
Ответ на: комментарий от AIv
╓─[santa@lain ~ $]
║
╙─> cat test.cpp
#include <iostream>
#include <chrono>
#include <cmath>

using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::steady_clock;

int main() {
        double d = 10.0;
        int di;

        steady_clock::time_point start = steady_clock::now();
        for (int i = 0; i < 100000; i++) {
                di = floor(d);
        }
        steady_clock::time_point end = steady_clock::now();
        std::cout << "floor() took "
                << duration_cast<microseconds>(end - start).count()
                << "us." << std::endl;

        start = steady_clock::now();
        for (int i = 0; i < 100000; i++) {
                di = static_cast<int>(d);
        }
        end = steady_clock::now();
        std::cout << "static_cast<>() took "
                << duration_cast<microseconds>(end - start).count()
                << "us." << std::endl;


        return 0;
}
╓─[santa@lain ~ $]
║
╙─> g++ -std=c++11 -O0 test.cpp -o test
╓─[santa@lain ~ $]
║
╙─> ./test 
floor() took 674us.
static_cast<>() took 334us.
x0r ★★★★★
()
Ответ на: комментарий от x0r

Хоть бы с -O2 скомпилировал, а то сейчас будут кричать «оно соптимизирет!!!!»

hired777
() автор топика
Ответ на: комментарий от x0r

Во первых, при сборке с оптимизацией будет ноль и там и там - результат то не используется. А без оптимизации говорить о «жырном рантайме» несерьезно - если лень воткнуть -O2, то производительность не волнует.

Во вторых, каст к int и floor дают вообще то разные результаты для отрицательных чисел. И как то так повелось, что обычно имеет смысл именно результат floor.

AIv ★★★★★
()
Ответ на: комментарий от hired777

почему это плохо для базовых типов?

Потому, что нужно думать: тут базовый тип или нет? Зачем создавать себе проблемы на ровном месте - просто используй всегда static_cast и не выеживайся заморачивайся.

Ну а кроме этого, static_cast как бы говорит нам, что именно хотел порграммист, защищает нас от ошибок и помогает IDE анализировать код.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)

void foo(const int & a);

Бессмысленно для базовых типов. Для структур и экземпляров классов смысл имеет, для базовых нет.

Dudraug ★★★★★
()
Ответ на: комментарий от x0r

Если логика не предвидит изменение переменной, то лучше это описать, и получить ошибку компиляции, если вдруг эту логику где-то нарушишь.

tff
()
Ответ на: комментарий от hired777

это не плохо, я особой разницы между static_cast и (type) не вижу, но и не вижу смысла тащить в плюсы сишные конструкции, в то время, как в крестах есть свой оператор.

x0r ★★★★★
()
Ответ на: комментарий от AIv

во первых речь шла о приведении типов. о значениях переменных чери не шло.

во вторых -О0 там поставленно сознательно именно для отключения оптимизации и не получения 0ms, для -О2 еще мишуры вокруг надо натыкать, you are welcome to improve the test.

x0r ★★★★★
()
Ответ на: комментарий от tff

может быть. с моей точки зрения изменения значения переданного параметра с видимостью этого изменения в родительском контексте уже прикрыто передачей по значению. а изнутри - хоть потоп, для меня дико видеть в коде const int param.

x0r ★★★★★
()
Ответ на: комментарий от x0r

$ g++ -O3 -ffast-math test.cpp -std=c++11 $ ./a.out floor() took 224us. static_cast<>() took 126us. $ clang++ -O3 -ffast-math test.cpp -std=c++11 $ ./a.out floor() took 323us. static_cast<>() took 37us. $ clang++ -O0 -ffast-math test.cpp -std=c++11 $ ./a.out floor() took 638us. static_cast<>() took 353us. $ g++ -O0 -ffast-math test.cpp -std=c++11 $ ./a.out floor() took 359us. static_cast<>() took 229us. $ g++ -O0 test.cpp -std=c++11 $ ./a.out floor() took 287us. static_cast<>() took 229us. $ clang++ -O0 test.cpp -std=c++11 $ ./a.out floor() took 364us. static_cast<>() took 199us. $ clang++ -O3 test.cpp -std=c++11 $ ./a.out floor() took 575us. static_cast<>() took 74us. $ g++ -O3 test.cpp -std=c++11 $ ./a.out floor() took 565us. static_cast<>() took 136us.

пометил обе переменный как volatile в первом случае, что бы конпелятор не выкинул их. Шланг обогнал гцц в плане каста double к int.

anonymous
()
Ответ на: комментарий от anonymous

ужас. все съехало. ну и ладно.

anonymous
()
Ответ на: комментарий от hired777

А можншь поянить почему это плохо для базовых типов?

1. Си плюс плюсные касты проще заметить, легче поиском находить. 2. Есть определённая защита от ошибок так как сам выбираешь какие преобразования разрешать, а не просто «приведи и пофиг, что получится».

DarkEld3r ★★★★★
()
Ответ на: комментарий от x0r

для меня дико видеть в коде const int param.

Аналогично... хотя и сталкивался с тем, что некоторые всё подряд таким образом передают - и enum или bool.

По моему, лишняя бессмысленная писанина. Плюс «непринято», то есть такой код будет большее количество людей напрягать.

Из интереса посмотрел, что на stackoverflow пишут - приводёт даже какие-то аргумент насчёт большей скорости передачи по значению. Сомневаюсь, но тоже аргумент против.

DarkEld3r ★★★★★
()
Ответ на: комментарий от x0r

во первых речь шла о приведении типов. о значениях переменных чери не шло.

Речь шла не о приведении типов вообще, а о приведении double к int. Конечно можно кастить, если не интересует результат. Зачем вообще обращать внимание на такие мелочи, как значение? Тип гораздо важнее!!!1111;-)

AIv ★★★★★
()
Ответ на: комментарий от DarkEld3r

приводёт даже какие-то аргумент насчёт большей скорости передачи по значению.

Для маленьких базовых типов ес-но. Конпелятору такой код гораздо проще оптимизировать.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Для маленьких базовых типов ес-но. Конпелятору такой код гораздо проще оптимизировать.

Вот как раз из-за оптимизации и сомневаюсь, что реальную разницу можно будет увидеть. Проверять лень, тем более, всё равно так не пишу.

DarkEld3r ★★★★★
()
Ответ на: комментарий от AIv

еще разок: приведение типа и шринк значения - разные вещи. в треде шло обсуждение приведения типов.

если нужно значение попереносить - ну дергай свой floor(), хто ж тебе мешает? я с такой необходимостью встречался только раз, когда гнал данные с GPU через выхлоп фрагментного шейдера. там так варьируются значение, шо мама не горюй, каст не подходил, приходилось делать floor + константный биас.

x0r ★★★★★
()
Ответ на: комментарий от x0r

А с моей точки зрения код программы должен отражать логику её работы, и для этого надо по возможности использовать средства языка, который используется. Это в такой же степени касается, например, типов переменных. Ведь здорово когда нельзя переменной, которая представляет стул присвоить значение животного. Если язык позволяет описать это естественным образом, то надо это по возможности использовать. Так читающему будет проще понять о чем же, собственно, идёт речь. Так то и ссылки можно передавать не константными, почему нет.

tff
()
Ответ на: комментарий от x0r

тащем то часто приходиться окргулять. Или искать отсечт сеточной фунции

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

AIv ★★★★★
()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от x0r

Меньше набирать, хоть и автокомплиты всякие. Использую static_cast, чтобы обратить внимание читателя кода, а всякие чар в инт и прочая обыденность - через с-шный синтаксис. Хотя чаще руководствуюсь принципом «чужого монастыря». И не считаю этот вопрос очень значительным.

next_time ★★★★★
()
Ответ на: комментарий от DarkEld3r

проще заметить

и эта обыденность так и лезет в глаза. почему тогда не юзать функцию «adding_two_numbers(int a, int b)» вместо «+» ?

легче поиском находить

Это почему же?

next_time ★★★★★
()
Ответ на: комментарий от next_time

и эта обыденность так и лезет в глаза. почему тогда не юзать функцию «adding_two_numbers(int a, int b)» вместо «+» ?

Ну да, лезет в глаза. И это отлично. Всё-таки касты (особенно, если это не статик каст) легко могут к ошибкам приводить (const_cast, reinterpret_cast) или тормозные (dynamic_cast). Так что лучше уж это будет сразу бросаться в глаза по мере чтения кода.

Кстати, ко второму пункту ты не придрался. Значит согласен?

Это почему же?

Допустим, надо найти все касты в файле. Что, по твоему, проще?

А если надо только определённый вид искать - то тем более.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

особенно, если это не статик каст

Не статик касты С-шным стилем не заменяю никогда.

Кстати, ко второму пункту ты не придрался. Значит согласен?

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

Допустим, надо найти все касты в файле. Что, по твоему, проще?

Не надо бояться человека с кастом.

А если надо только определённый вид искать - то тем более.

Как раз таки С-шные быстрее

next_time ★★★★★
()
Ответ на: комментарий от next_time

Не статик касты С-шным стилем не заменяю никогда.

Ну значит, по существу, нам особо спорить и не о чём.

Правда, я всегда пользуюсь статик кастом, но это скорее для однородности и дело привычки.

Впрочем, есть у меня один и более объективный аргумент. Если ты применишь статик каст, но он не может сделать требуемого, то получишь сообщение об ошибке во время компиляции. Сишный каст молча проглотит. Более актуально для новичков, но не вижу ничего плохого в дополнительной проверке. При рефакторинге, опять же, можно напороться...

Не надо бояться человека с кастом.

Это не ответ.

Как раз таки С-шные быстрее

Или я тебя не понял или ты меня. Допустим, хочется найти все конст касты в файле/проекте. С с++ кастами это делается легко, а с сишными (если использовать только их) как?

И в каком случае сишные быстрее тоже любопытно.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Или я тебя не понял или ты меня. Допустим, хочется найти все конст касты в файле/проекте.

Я не понял. Потому что обсуждение шло в контесте именно статик кастов. Предположил, что речь идёт о поиске всех операций приведения к определённому типу.

Это не ответ.

Я имел в виду то, что статик приведение - в общем-то безопасная операция. В отличие от прочих приведений, есс-но.

next_time ★★★★★
()
Ответ на: комментарий от next_time

И как мне найти все static_cast'ы в проекте? С учётом того что половина из них сишные, а типа к которому приводят я не знаю?

И да, что такого безопасного в static_cast'е?

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

И да, что такого безопасного в static_cast'е?

что в них небезопасного? чар в инт перевести - небезопасное преобразование?

И как мне найти все static_cast'ы в проекте?

их не надо искать - это всё равно, что все операции «+» искать - можно конечно, но зачем?

next_time ★★★★★
()
Ответ на: комментарий от next_time

что в них небезопасного? чар в инт перевести - небезопасное преобразование?

А если int в char?

но зачем?

Например чтобы выпилить. Или найти место где у тебя происходит усечение.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

А если int в char?

(char)getchar() - что здесь небезопасного?

Например чтобы выпилить.

зачем?

Или найти место где у тебя происходит усечение.

Такие места быстрее найдутся, если помечать статик кастом только небезопасные операции.

next_time ★★★★★
()
Ответ на: комментарий от x0r

Я тут еще один вариант придумал:

typedef int Num;

Num foo(Num a, Num b) {
  return a + b;
}

Потом резко понадобилась длинная арифметика и мы просто поменяли typedef на полноценный класс:

class Num {
  Num operator+ (const Num & other) const;
  ...
};

Понятно, что если бы мы изначально передавали по ссылке проблем было бы меньше. Или мой пример на грани фантастики?

hired777
() автор топика
Ответ на: комментарий от hired777

Потом резко понадобилась длинная арифметика и мы просто поменяли typedef на полноценный класс

преждевременная оптимизация - враг разработки :)

x0r ★★★★★
()
Ответ на: комментарий от next_time

(char)getchar() - что здесь небезопасного?

а теперь подай на вход текстовый файл в кодировке windows-1251, в котором есть строчная буква «я» и найди EOF.

cdslow ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.