return value
От: aloneguid  
Дата: 30.09.07 13:21
Оценка:
Здраствуйте,

Объясните плиз происходит ли при return создание нового вектора и копирование, и почему?

vector<char> function1(...)
{
  vector<char> v;
  ...
  return v;
}


Спасибо!
Re: return value
От: remark Россия http://www.1024cores.net/
Дата: 30.09.07 13:33
Оценка: 2 (1) +1
Здравствуйте, aloneguid, Вы писали:

A>Здраствуйте,


A>Объясните плиз происходит ли при return создание нового вектора и копирование, и почему?


A>
A>vector<char> function1(...)
A>{
A>  vector<char> v;
A>  ...
A>  return v;
A>}
A>


A>Спасибо!


Происходит от 0 до 1 созданий нового вектора и копирований.

В таком коде:
vector<char> v = function1();


Происходит от 0 до 2 созданий нового вектора и копирований.

В таком коде:
vector<char> const& v = function1();


Происходит от 0 до 1 созданий нового вектора и копирований.

Сколько конкретно — зависит от компилятора, настроек компилятора и реализации объекта. На количество созданий/копирований полагаться нельзя. Тут компилятор в праве подавлять даже вызовы функций, определённые пользователем и с побочными эффектами.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: return value
От: Аноним  
Дата: 01.10.07 05:53
Оценка:
Здравствуйте, remark, Вы писали:

R>В таком коде:

R>
R>vector<char> const& v = function1();
R>

R>Происходит от 0 до 1 созданий нового вектора и копирований.
Может это верно для
const vector<char> const& v = function1();

?
Re[3]: return value
От: remark Россия http://www.1024cores.net/
Дата: 01.10.07 05:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, remark, Вы писали:


R>>В таком коде:

R>>
R>>vector<char> const& v = function1();
R>>

R>>Происходит от 0 до 1 созданий нового вектора и копирований.
А>Может это верно для
А>
А>const vector<char> const& v = function1();
А>

А>?



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


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: return value
От: Аноним  
Дата: 01.10.07 06:15
Оценка:
Здравствуйте, remark, Вы писали:

A>>Объясните плиз происходит ли при return создание нового вектора и копирование, и почему?


R>Происходит от 0 до 1 созданий нового вектора и копирований.

А можно с пояснениями? Желательно всех примеров...
Re: return value
От: AKh  
Дата: 01.10.07 06:17
Оценка:
Здравствуйте, aloneguid, Вы писали:

A>Здраствуйте,


A>Объясните плиз происходит ли при return создание нового вектора и копирование, и почему?


A>
A>vector<char> function1(...)
A>{
A>  vector<char> v;
A>  ...
A>  return v;
A>}
A>


A>Спасибо!


Передача по значению может производить копирование.
Re[4]: return value
От: Аноним  
Дата: 01.10.07 06:20
Оценка:
Здравствуйте, remark, Вы писали:

R>

R>Это идентично. Я думаю, твой компилятор должен был выдать варнинг
R>
Недавно вроде обсуждали, что const T& имеет право продлить время жизни объекта, T& — нет
Re[5]: return value
От: Кодт Россия  
Дата: 01.10.07 09:46
Оценка:
Здравствуйте, <Аноним>, Вы писали:

R>>

R>>Это идентично. Я думаю, твой компилятор должен был выдать варнинг
R>>
А>Недавно вроде обсуждали, что const T& имеет право продлить время жизни объекта, T& — нет

С другой стороны,
1) const T& == T const& == const T const& == T const const const const&
2) T& ref = return_T_value() — является апокрифом. На VC оно не просто имеет, а обязано продлевать время жизни объекта (равно как T const&), а на остальных — получишь ошибку компиляции.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: return value
От: Кодт Россия  
Дата: 01.10.07 10:18
Оценка: 2 (1)
Здравствуйте, <Аноним>, Вы писали:

R>>Происходит от 0 до 1 созданий нового вектора и копирований.

А>А можно с пояснениями? Желательно всех примеров...

Компилятор вправе делать оптимизации возвращаемых значений (RVO и NRVO).
NRVO, впрочем, встречается реже.

Механизм здесь вот какой: возвращение структуры из функции реализуется как скрытый out-параметр.
template<class T> struct aligned_storage;
// неинициализированная память, sizeof(aligned_storage<T>)==sizeof(T),
// выравненная наилучшим для T способом.

/////////////////////////////////////////
// возвращение

T foo()
{
    return T(...);
    /////////////////
    return bar(...);
    /////////////////
    T local(...);
    ....
    return local;
}
// сделано так
T const& foo_(aligned_storage<T>& retval)
{
    T tmp(...);
    return *new (&retval) T(tmp); // копирование
    // либо
    return *new (&retval) T(...); // RVO

    /////////////////
    T tmp = bar(...);
    return *new (&retval) T(tmp); // копирование
    // либо
    return bar_(retval, ...); // RVO

    /////////////////
    T local(...);
    ....
    return *new (&retval) T(tmp); // копирование
    // либо
    T& local = *new (&retval) T(...); // NRVO - разместили локальную переменную прямо в retval
    ....
    return *local;
}

/////////////////////////////////////////
// приём

TBase& x = foo();
/////////////
T y = foo();
/////////////
TBaze z = foo();

// сделано так

aligned_storage<T> x_; // вот так работает механизм продления жизни!
TBase& x = *new(&x_) T(foo_(aligned_storage<T>())); // копирование
// либо
aligned_storage<T> x_;
T& x = foo_(x_); // RVO

/////////////

T y (foo_(aligned_storage<T>())); // копирование
// либо
aligned_storage<T> y_;
T& y = foo_(y_); // RVO

/////////////

TBase z(foo_(aligned_storage<T>())); // копирование
// без вариантов, поскольку foo возвращает иной тип, чем ожидаемое

Итого получаем
TBase& x = foo(); // 0..1 копирование здесь, 0..1 копирование в foo() = 0..2
T      y = foo(); // 0..1 копирование здесь, 0..1 копирование в foo() = 0..2
TBaze  z = foo(); //    1 копирование здесь, 0..1 копирование в foo() = 1..2
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: return value
От: Кодт Россия  
Дата: 01.10.07 10:21
Оценка:
Здравствуйте, AKh, Вы писали:

AKh>Передача по значению может производить копирование.


К-сть — с-а т.!

В данном случае — с наибольшей вероятностью будет произведено копирование.
Потому что
1) NRVO — редкость
2) у вектора нет move constructor (эх, дождёмся ли?)
3) а через регистры его передавать нельзя (во-первых, большой объект, а во-вторых, конструкторы/деструктор нетривиальные)
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: return value
От: remark Россия http://www.1024cores.net/
Дата: 01.10.07 10:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, AKh, Вы писали:


AKh>>Передача по значению может производить копирование.


К>К-сть — с-а т.!


К>В данном случае — с наибольшей вероятностью будет произведено копирование.

К>Потому что
К>1) NRVO — редкость
К>2) у вектора нет move constructor (эх, дождёмся ли?)
К>3) а через регистры его передавать нельзя (во-первых, большой объект, а во-вторых, конструкторы/деструктор нетривиальные)


std::vector<char> function1()
{
    std::vector<char> v;
    v.push_back(0);
    return v;
}

int main()
{
    std::vector<char> v = function1();
    v.push_back(0);
}



int main()
{
004015A0  push        0FFFFFFFFh 
004015A2  push        offset __ehhandler$_main (401F88h) 
004015A7  mov         eax,dword ptr fs:[00000000h] 
004015AD  push        eax  
004015AE  mov         dword ptr fs:[0],esp 
004015B5  sub         esp,14h 
    std::vector<char> v = function1();
004015B8  lea         eax,[esp+4] 
004015BC  push        eax  
004015BD  call        function1 (401520h) 
004015C2  add         esp,4 
    v.push_back(0);
004015C5  lea         ecx,[esp+3] 
004015C9  push        ecx  
004015CA  lea         ecx,[esp+8] 
004015CE  mov         dword ptr [esp+20h],0 
004015D6  mov         byte ptr [esp+7],0 
004015DB  call        std::vector<char,std::allocator<char> >::push_back (4014B0h) 
}
004015E0  mov         eax,dword ptr [esp+8] 
004015E4  test        eax,eax 
004015E6  mov         dword ptr [esp+1Ch],0FFFFFFFFh 
004015EE  je          main+62h (401602h) 
004015F0  mov         edx,dword ptr [esp+10h] 
004015F4  sub         edx,eax 
004015F6  push        edx  
004015F7  push        eax  
004015F8  lea         ecx,[esp+0Ch] 
004015FC  call        dword ptr [__imp_std::allocator<char>::deallocate (402038h)] 
00401602  mov         ecx,dword ptr [esp+14h] 
00401606  xor         eax,eax 
00401608  mov         dword ptr fs:[0],ecx 
0040160F  add         esp,20h 
00401612  ret



Visual Studio 2005



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: return value
От: Кодт Россия  
Дата: 01.10.07 12:06
Оценка:
Здравствуйте, remark, Вы писали:

<>

Это ты показал, во что развернулся main(). Кто бы сомневался, здесь RVO сделано.
А теперь посмотри, во что превратилась function1.

Кстати, интересно, что при /Ox — NRVO выполнилось. А причина этому — тривиальная реализация конструктора без параметров! (Попросту, забили структуру нулями). Круто!
Вот если бы конструктор был затейливым — то могли и обломиться...
PUBLIC    ?function1@@YA?AV?$vector@DV?$allocator@D@std@@@std@@XZ ; function1
_TEXT    SEGMENT
$T18900 = 8                        ; size = 1
___$ReturnUdt$ = 8                    ; size = 4
?function1@@YA?AV?$vector@DV?$allocator@D@std@@@std@@XZ PROC ; function1

; 5    :     std::vector<char> v;

    xor    eax, eax
    push    esi
    mov    esi, DWORD PTR ___$ReturnUdt$[esp] ; вот оно, NRVO
    mov    DWORD PTR [esi+4], eax
    mov    DWORD PTR [esi+8], eax
    mov    DWORD PTR [esi+12], eax

; 6    :     v.push_back(0);

    mov    BYTE PTR $T18900[esp], al
    lea    eax, DWORD PTR $T18900[esp]
    push    eax
    mov    ecx, esi
    call    ?push_back@?$vector@DV?$allocator@D@std@@@std@@QAEXABD@Z ; std::vector<char,std::allocator<char> >::push_back

; 7    :     return v;

    mov    eax, esi
    pop    esi

; 8    : }

    ret    0
?function1@@YA?AV?$vector@DV?$allocator@D@std@@@std@@XZ ENDP ; function1
_TEXT    ENDS


PUBLIC    _main
_TEXT    SEGMENT
$T19060 = -17                        ; size = 1
$T18978 = -17                        ; size = 1
_v$ = -16                        ; size = 16
_main    PROC

; 11   : {

    sub    esp, 20                    ; 00000014H
    push    ebx

; 12   :     std::vector<char> v = function1();
; компилятор проинлайнил function1, поэтому результат нечестный

    xor    ebx, ebx
    lea    eax, DWORD PTR $T19060[esp+24]
    push    eax
    lea    ecx, DWORD PTR _v$[esp+28]
    mov    DWORD PTR _v$[esp+32], ebx
    mov    DWORD PTR _v$[esp+36], ebx
    mov    DWORD PTR _v$[esp+40], ebx
    mov    BYTE PTR $T19060[esp+28], bl
    call    ?push_back@?$vector@DV?$allocator@D@std@@@std@@QAEXABD@Z ; std::vector<char,std::allocator<char> >::push_back

; но если мы введём косвенность (вызов функции по указателю)...
; 12   :     std::vector<char> v = f();

    lea    eax, DWORD PTR $T18983[esp]
    sub    esp, 36                    ; 00000024H
    push    eax
    call    DWORD PTR ?f@@3P6A?AV?$vector@DV?$allocator@D@std@@@std@@XZA ; f
    add    esp, 4
    push    eax
    lea    ecx, DWORD PTR _v$[esp+40]
    call    ??0?$vector@DV?$allocator@D@std@@@std@@QAE@ABV01@@Z ; std::vector<char,std::allocator<char> >::vector<char,std::allocator<char> >
    mov    eax, DWORD PTR $T18983[esp+40]
    test    eax, eax
    je    SHORT $LN8@main
    push    eax
    call    ??3@YAXPAX@Z                ; operator delete
    add    esp, 4
$LN8@main:

; 13   :     v.push_back(0);

    lea    ecx, DWORD PTR $T18978[esp+24]
    push    ecx
    lea    ecx, DWORD PTR _v$[esp+28]
    mov    BYTE PTR $T18978[esp+28], bl
    call    ?push_back@?$vector@DV?$allocator@D@std@@@std@@QAEXABD@Z ; std::vector<char,std::allocator<char> >::push_back

; 14   : }

    mov    eax, DWORD PTR _v$[esp+28]
    cmp    eax, ebx
    pop    ebx
    je    SHORT $LN39@main
    push    eax
    call    ??3@YAXPAX@Z                ; operator delete
    add    esp, 4
$LN39@main:
    xor    eax, eax
    add    esp, 20                    ; 00000014H
    ret    0
_main    ENDP
_TEXT    ENDS
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.