На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: JoeUser, Qraizer
  
> RVO в разных единицах трансляции
    Собственно сабж. Умеют ли современные компиляторы такое? Т.е. есть
    1.cpp
    ExpandedWrap disabled
      std::vector<int> f()
      {
          std::vector<int> v;
          //...
          return v;
      }

    2.cpp
    ExpandedWrap disabled
      std::vector<int> v = f();

    Будут ли лишние вызовы конструктора копирования?
    Цитата TheMachine @
    т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
      Цитата shm @
      Будут ли лишние вызовы конструктора копирования?


      А ты поставь вместо вектора std::unique_ptr и увидишь.
        Олег М, меня интересует общая тенденция, а не как реализовано у конкретного компилятора с конкретными настройками.
        Цитата TheMachine @
        т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
          А что, разве общая тенденция не такая, чтоб использовать move-конструктор при return? Хотя, по-любому, я там всегда делаю std::move. Так, на всякий случай.
            Цитата Олег М @
            отя, по-любому, я там всегда делаю std::move. Так, на всякий случай.

            Надо ли писать return std::move(local_var)?
            Но в данном случае это оффтоп.
            Цитата TheMachine @
            т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
              Цитата shm @
              Надо ли писать return std::move(local_var)?
              Но в данном случае это оффтоп


              Может и оффтоп. Но единственное, что я понял – что лучше всегда делать move.
              А вообще, такое поведение как–то может зависеть от единиц трансляции, в принципе?
              Т.е. я переношу функцию, которая возвращает unique_ptr в другой файл и код перестает компилироваться?
                Раздел 12.8.3 стандарта (N4618) [class.copy.elision]:
                Цитата
                When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
                object, even if the constructor selected for the copy/move operation and/or the destructor for the object
                have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
                operation as simply two different ways of referring to the same object. If the first parameter of the selected
                constructor is an rvalue reference to the object’s type, the destruction of that object occurs when the target
                would have been destroyed; otherwise, the destruction occurs at the later of the times when the two objects
                would have been destroyed without the optimization. This elision of copy/move operations, called copy
                elision , is permitted in the following circumstances (which may be combined to eliminate multiple copies):
                (1.1)
                in a return statement in a function with a class return type, when the expression is the name of
                a non-volatile automatic object (other than a function parameter or a variable introduced by the
                exception-declaration of a handler (15.3)) with the same type (ignoring cv-qualification) as the function
                return type, the copy/move operation can be omitted by constructing the automatic object directly
                into the function call’s return object
                — (1.2)
                in a throw-expression (5.17), when the operand is the name of a non-volatile automatic object (other than
                a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost
                enclosing try-block (if there is one), the copy/move operation from the operand to the exception
                object (15.1) can be omitted by constructing the automatic object directly into the exception object
                — (1.3)
                when the exception-declaration of an exception handler (Clause 15) declares an object of the same type
                (except for cv-qualification) as the exception object (15.1), the copy operation can be omitted by
                treating the exception-declaration as an alias for the exception object if the meaning of the program will
                be unchanged except for the execution of constructors and destructors for the object declared by the
                exception-declaration. [ Note: There cannot be a move from the exception object because it is always an
                lvalue. —end note ]

                Таким образом:
                а) Это должно работать между модулями в том числе - ссылка на переменную, в которой можно разместить результат, передаётся скрытым параметром функции.
                б) Запись return std::move(a); - это отключение RVO/copy elision. К слову, анализатор clang tidy на такие вещи матерится.
                "Математики думают, что Бог в уравнениях, нейрологи уверены, что Бог в мозге, а программисты уверены, что Бог — один из них."
                Морган Фриман
                Мой учебник C++ - это просто!
                Я на blogspot.com.
                  Flex Ferrum, спс.

                  Добавлено
                  Цитата Flex Ferrum @
                  в которой можно разместить результат, передаётся скрытым параметром функции.

                  Я правильно понимаю, что если нет возможности использовать RVO, то компилятор создаст временный объект и передаст по ссылке?
                  Цитата TheMachine @
                  т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
                    Цитата shm @
                    Я правильно понимаю, что если нет возможности использовать RVO, то компилятор создаст временный объект и передаст по ссылке?

                    Как-то так, да, если я тебя правильно понял. Место, где размещать результат выполнения функции, всё равно ведь как-то передаётся в вызов. Просто с copy elision запись типа:
                    ExpandedWrap disabled
                      std::string Foo(...)
                      {
                      std::string result("a");
                      result += "b";
                      return result;
                      }

                    сразу разместит result в скоупе вызывающей функции. А без RVO - будет выполнено копирование из временной переменной в возвращаемое значение.
                    "Математики думают, что Бог в уравнениях, нейрологи уверены, что Бог в мозге, а программисты уверены, что Бог — один из них."
                    Морган Фриман
                    Мой учебник C++ - это просто!
                    Я на blogspot.com.
                    1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script Execution time: 0,1093 ]   [ 15 queries used ]   [ Generated: 20.09.17, 00:03 GMT ]