1. C++ / Говнокод #23241

    +1

    1. 1
    2. 2
    3. 3
    CoolIntf::GetInstance().DoSomething();
    CoolIntf::GetInstance().DoSomethingElse();
    CoolIntf::GetInstance().DoAnything()

    для случая когда GetInstance() не инлайнится, кто-нибудь в крестах какое решение (без ручного введения временной переменной) для такого кода придумал?
    единственное что нашел это вот это: https://stackoverflow.com/a/2279253 .
    потому что "with" слишком общее слово которое в ж не гуглится.

    Запостил: Dummy00001, 04 Августа 2017

    Комментарии (38) RSS

    • а возвращение инстанса достаточно дорогая операция чтобы настловать мозг?
      Ответить
      • из встроенщины. и дорого (потому что все железо убогое и тормозное), и вызов занимает 4-8 байт.

        первый вызов нужен, но последующие хочется как то убрать.
        Ответить
        • А что плохого в ручном введении переменной? Вроде не так много писанины добавляет.
          auto& p = CoolIntf::GetInstance();
          p.DoSomething();
          p.DoSomethingElse();
          p.DoAnything();
          Ответить
          • > А что плохого [...]

            (1) там еще авто нету.
            (2) ничего, но я хочу что бы это `p` было в какой scope загнано.

            я пробовал извраты на тему `for (auto& p = Aaa::GetInst(); ; ) { /* body */'; break; }`. но там было Нное количество мелких граблей (наброски в офисе - так не вспомню).

            главное: это очень мелкая проблема что бы для неё код перерасхерачивать.
            Ответить
            • Так в плюсах же вроде можно делать scope просто составным оператором?
              do_stuff();
              {
                CoolIntf& I = CoolIntf::GetInstance();
                I.DoSomething();
                I.DoSomethingElse();
                //Здесь I выйдет из скопа и отработает деструктор ~CoolIntf(), если есть.
              }
              do_more_stuff();
              Ответить
              • да. но, повторюсь: это очень мелкая проблема что бы для неё код перерасхерачивать.

                то что я в офисе пытался делать, набросок:
                #include <stdio.h>
                
                #define WITH1(oo)	for (oo, bool xxx = true; xxx; xxx = false)
                
                struct Tt {
                	static Tt tt;
                	static Tt& GetInst() { return tt; };
                	void important_stuff() {
                		printf("Hello World\n");
                	};
                };
                
                int main()
                {
                	auto x = Tt::GetInst();
                	x.important_stuff();
                
                	WITH1( auto t = Tt::GetInst() ) {
                		t.important_stuff();
                	}
                }


                но как выяснилось, в `for()` нельзя переменные разных типов объявлять.
                Ответить
                • Ну ок. Хотя стоит сначала посмотреть, не оптимизирует ли компилятор это дело?
                  Ответить
                  • нет, не оптимизирует. компилятор не имеет права менять количество вызовов функций. может быть только если он "видит" реализацию, и знает что нет побочных эффектов. но к сожалению эти GetInstance() лежат в .cpp и шансов мало это поменять. хотя ради эксперимента стоит попробовать положить их в .hpp и посмотреть какой эффект это будет иметь.
                    Ответить
                    • gcc может оптимизировать вызовы какого-нибудь [[gnu::const]]. Там же еще link-time optimization есть, или компилятор не дорос?
                      Ответить
                      • раньше LTO этого не умело. сейчас? - не знаю.

                        с этими гну фичами ни разу н игрался - https://stackoverflow.com/questions/29117836/attribute-const-vs-attribute-pure-in-gnu-c
                        Ответить
                • Чем использование составного оператора отличается от твоего фора?
                  Ответить
                  • > составного оператора

                    по не-русски?

                    я на просто пытался прикрутить типичный `with` других языков к крестам.
                    Ответить
              • > //Здесь I выйдет из скопа и отработает деструктор ~CoolIntf(), если есть.

                Какой ещё деструктор, там же ссылка, тем более неконстантная.
                Ответить
            • if  (auto&p = Aaa::GetInstance()) {
                  p.DoSomething();
                  p.DoSomethingElse();
              }
              З.Ы. Хотя if странно смотрится, да.
              Ответить
              • #define with if
                Ответить
                • #define WITH(var, expr) if (auto* var = &(expr))
                  
                  WITH(p, Aaa::GetInstance()) {
                      p->DoSomething();
                      p->DoSomethingElse();
                  }
                  
                  Ответить
                  • да, твое первое криво (референс vs bool). но второй вариант уже намного лучше. как по мне, даже и без WITH() дефайна ОК.

                    ЗЫ жаль что к моему текущему проекту не применимо, т.к. на референсах все. указатели всегда надо проверять и кидать ошибку если нулл.

                    ЗЗЫ а вот такое редиско-компилер не съедает (что с авто, что с конкретным типом):
                    if ((Tt& t = (Tt::GetInst()), true)) {
                       printf( "%d\n", t.answer() );
                    }
                    Ответить
                    • template <typename T>
                      struct WithHelper : public T {
                          operator bool() { return true; }
                      };
                      
                      template <typename T>
                      WithHelper<T>& MakeWithHelper(T& ref) {
                          return static_cast<WithHelper<T>&>(ref);
                      }
                      
                      #define WITH(var, expr) if (auto& var = MakeWithHelper(expr))
                      
                      WITH(p, Aaa::GetInstance()) {
                          p.DoSomething();
                          p.DoSomethingElse();
                      }
                      
                      Ответить
                      • ух, жестоко
                        "счастливого дебага", ага
                        Ответить
                      • а это свежая идея!

                        в конце конечно изврат получается, но принцип интересный.

                        я еще попытался просто оператор сравнения перекрыть и с дамми классом сравнивать (вместо простой бул конверсии) но чего то мой гцц это отказывается в if'е переваривать (`(auto& x = WithHelper(Aaa::GetInstance())) == WithCompareDummy()`).
                        Ответить
                        • Включай C++17, там тебе сделал решение
                          if (Aaa& p = Aaa::GetInstance(); true) {
                            p.DoSomething();
                            p.DoSomethingElse();
                          }
                          Ответить
                          • IAR понадобилось 6 (шесть) лет что бы С++11 сделать. С++17 я думаю что еще столько же лет придётся ждать. и потом еще столько же ждать пока это до проектов дотечёт...

                            что есть весьма обидно, потому что много фич как раз для встроенщины полезны (энумы, конст-экспр).
                            Ответить
                      • А почему статик каст, а не реинтерпред?

                        Или он для обратного преобразования?
                        Ответить
                        • Потому что зачем юзать reinterpret, если и static'а хватит.
                          Ответить
                          • Кмк, reinterpret здесь вообще не корректен.
                            Ответить
                            • А статик каст корректен?
                              Ответить
                              • Статик каст тут уместен, он по сути конструктор враппера вызывает. Вообще все преобразования потомок <-> родитель нужно выполнять либо через static_cast, либо через dynamic_cast. Они правильно подсчитают смещения объектов в родительских объектах.
                                А reinterpret нужен, чтобы сказать "будем считать, что в этих байтах лежит что-то другое", без всякого подсчёта смещений.
                                Ответить
                                • Там каст ссылки в ссылку, он не создает новый объект. Да и нет у WithHelper конструктора из базового класса.
                                  Ответить
                                  • Ты прав, я ерунду сморозил. Враппер никогда не создаётся, тут мы просто компилятор делаем счастливым. У ссылки меняется только тип, поскольку T это первый объект во враппере и имеет тот же адрес.
                                    Ответить
                  • Aaa::WithInstance([&](Aaa& p) {
                      p.DoSomething();
                      p.DoSomethingElse();
                    });
                    Ответить
      • Тебя заминусовали https://habrahabr.ru/post/334988/#comment_10346380
        Ответить
    • GetInstance()->DoSomething()->DoSomethingElse()->DoAnything();
      Ответить
      • только с войд методами работает. которые все нужно конвертить.
        Ответить
    • синглтоны ненужны
      Ответить
      • да.

        но в данном конкретном проекте там стоит проверка (и обработка) ошибки доступа к глобальным объектам до того как инициализация оного завершилась. сама проверка - один глупый if. а вот вход в обработчик фатальных ошибок - толстый.
        Ответить

    Добавить комментарий