Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
802 / 532 / 157
Регистрация: 27.01.2015
Сообщений: 3,025
Записей в блоге: 1
1

Копирование объектов std::unique_ptr

28.06.2017, 08:18. Показов 2703. Ответов 20
Метки нет (Все метки)

привет, столкнулся с такой ситуацией, что вроде как копировать объекты std::unique_ptr запрещено,
но тем не менее такой код компилируется:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <memory>
using namespace std;
 
unique_ptr<int> clone(int n)
{
    unique_ptr<int> p{ new int{ n } };
    // какая нибудь работа
    return p;
}
 
int main()
{
    clone(3);
}
Этот код скомпилировался по причине nrvo?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.06.2017, 08:18
Ответы с готовыми решениями:

Копирование std::unique_ptr в структуре
Есть структуры и vector struct myStruct { int a; int b; void* param; }; struct sSetup {...

Копирование объектов std::thread
В учебнике Энтони Уильямса есть простой пример класса scoped_thread, присоединяющего поток в...

Использование std::unique_ptr
Есть в коде подобная конструкция, вылетает исключение на этапе очистки памяти. С чем это может быть...

Компилятор не видит std::unique_ptr
Не создается unique_ptr int main(int argc, char *argv) { QCoreApplication a(argc, argv);...

20
Любитель чаепитий
3580 / 1681 / 518
Регистрация: 24.08.2014
Сообщений: 5,698
Записей в блоге: 1
28.06.2017, 08:51 2
если объект создается в функции и потом возвращается оттуда, то срабатывает конструктор перемещения.
по такому же принципу и std::make_unique работает.
0
802 / 532 / 157
Регистрация: 27.01.2015
Сообщений: 3,025
Записей в блоге: 1
28.06.2017, 09:30  [ТС] 3
GbaLog-, все равно непонятно, это в стандарте чтоли прямо написано, что
Цитата Сообщение от GbaLog- Посмотреть сообщение
если объект создается в функции и потом возвращается оттуда, то срабатывает конструктор перемещения
?
0
Форумчанин
Эксперт CЭксперт С++
8169 / 5017 / 1436
Регистрация: 29.11.2010
Сообщений: 13,455
28.06.2017, 10:19 4
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
все равно непонятно, это в стандарте чтоли прямо написано, что
Этот вопрос подробно рассмотрен у Майерса в "Современный и эффективный С++". ЕМНИП, такая вещь как elision (RVO, NRVO) в стандарте явно не прописывают, но о них все знают. Это техника оптимизации компилятором, а не правило языка.
Тут явно имеет место оптимизация с перемещением временного объекта.
А если бы она не сработала - вы получили бы ошибку, так что коли компилится - всё ок.
1
Любитель чаепитий
3580 / 1681 / 518
Регистрация: 24.08.2014
Сообщений: 5,698
Записей в блоге: 1
28.06.2017, 10:52 5
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
это в стандарте чтоли прямо написано
в с++17.
http://www.open-std.org/jtc1/s... 135r1.html
но это не точно, ибо мой английский оставляет желать лучшего.
2
802 / 532 / 157
Регистрация: 27.01.2015
Сообщений: 3,025
Записей в блоге: 1
28.06.2017, 11:02  [ТС] 6
Цитата Сообщение от MrGluck Посмотреть сообщение
RVO, NRVO
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
Этот код скомпилировался по причине nrvo?
///
0
15104 / 8106 / 1956
Регистрация: 30.01.2014
Сообщений: 13,771
28.06.2017, 11:29 7
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
Этот код скомпилировался по причине nrvo?
Нет конечно.
RVO тут только позволит избежать вызова конструктора перемещения. Естественно, что с вызовом конструктора, что без, наблюдаемое поведение не изменится.
0
Эксперт С++
8426 / 4099 / 894
Регистрация: 15.11.2014
Сообщений: 9,200
28.06.2017, 12:18 8
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
Этот код скомпилировался по причине nrvo?
нет. когда функция возвращает по значению.
и из неё делается return - провоцируется запуск move-версий конструктора
(или оператора присвоения)

рассмотрим пример:
http://rextester.com/AGY1867

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <memory>
#include <iostream>
using namespace std;
 
unique_ptr<int> clone(int n)
{
    unique_ptr<int> p{ new int{ n } };
    // какая нибудь работа
    return p;
}
 
 
 
//-------------------------------------------------------------------------        
//---------- кросс-платформенный макрос отображения имени функции ---------
//-------------------------------------------------------------------------        
 
#if defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW__)
    #define dFUNCTION __PRETTY_FUNCTION__
#else
    #ifdef _MSC_VER
        #define dFUNCTION __FUNCSIG__
    #else
        #define dFUNCTION __FUNCTION__
    #endif
#endif
 
#define dVIEW_FUNCTION std::cout << dFUNCTION << std::endl
 
//-------------------------------------------------------------------------         
//-------------------------------------------------------------------------        
//-------------------------------------------------------------------------       
 
struct sample
{
    sample()         { dVIEW_FUNCTION; }
    sample(sample&&) { dVIEW_FUNCTION; }
    
    sample(const sample&) = delete;
    
    sample& operator=(const sample&) = delete;
    
    sample& operator=(sample&&) { dVIEW_FUNCTION; return *this; }
};
 
 
 
sample foo()
{
    sample s;
    return s;
}
 
 
int main()
{
    clone(3);
    
    sample s = foo(); //конструктор перемещения
    //(может быть оптимизирован согласно copy elision)
    
    s = foo(); //оператор= перемещения
    
}
1
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 18:14 9
На мой взгляд не факт что срабатывает именно перемещение

Вот в следующем примере результат работы функции успешно "копируется" в переменную(а не должен).
Выглядит так как будто функция просто заинлайнилась и ничего нигде не копировалось

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//g++  5.4.0
 
#include <iostream>
#include <memory>
 
using namespace std;
 
unique_ptr<int> clone(int n)
{
    unique_ptr<int> p{ new int{ n } };
    // какая нибудь работа
    return p;
}
 
int main()
{
   auto p = clone(3);
}
Добавлено через 1 минуту
http://rextester.com/DLHR98678
0
Эксперт С++
8426 / 4099 / 894
Регистрация: 15.11.2014
Сообщений: 9,200
28.06.2017, 18:46 10
Цитата Сообщение от Undisputed Посмотреть сообщение
Вот в следующем примере результат работы функции успешно "копируется" в переменную(а не должен).
тот факт, что у unique_ptr конструктор копии вообще запрещен
вас никак не смущает?

и где вы вообще тут увидели пример копирования?
0
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 19:20 11
hoggy,
Копируется я взял в кавычки)

Я вот чего недопониманимаю:

По идее если отбросить все оптимизации то расклад возвращаемого значения из функции если не ошибаюсь таков:
- на стеке функции создаётся объект
- возвращается копия обьекта созданного на стеке функции
- вызывающая сторона создаёт ещё одну копию

Но в вашем примере выше если я ничего не напутал перемещение срабатывает сразу из стека функции в вызывающую сторону, но это оптимизация(а что говорит стандарт по этому поводу?)

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

Или я чего то недопонимаю?
0
Don't worry, be happy
17165 / 10049 / 1934
Регистрация: 27.09.2012
Сообщений: 25,035
Записей в блоге: 1
28.06.2017, 19:20 12
Цитата Сообщение от Undisputed Посмотреть сообщение
На мой взгляд не факт что срабатывает именно перемещение
Из стандарта:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration , and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.
0
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 19:20 13
Поэтому я и подумал что тут больше может подойти инлайн нежели перемещение...
0
Don't worry, be happy
17165 / 10049 / 1934
Регистрация: 27.09.2012
Сообщений: 25,035
Записей в блоге: 1
28.06.2017, 19:22 14
Цитата Сообщение от Undisputed Посмотреть сообщение
- возвращается копия обьекта созданного на стеке функции
- вызывающая сторона создаёт ещё одну копию
Сначала будет попытка перемещения. Если переместить нельзя, то будет выбрано копирование.

Цитата Сообщение от Undisputed Посмотреть сообщение
Поэтому я и подумал что тут больше может подойти инлайн нежели перемещение...
Вообще никак не связанно.

Добавлено через 1 минуту
Цитата Сообщение от Undisputed Посмотреть сообщение
Более того, оптимизации такого рода насколько я понимаю не являются частью стандарта
Являются. copy elision официально разрешен.
1
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 19:25 15
Croessmah,
Увы затрудняюсь прочесть текст, а гугл транслейт нормально не переводит(

Добавлено через 48 секунд
Разрешён не значит же то обязателен )

Добавлено через 15 секунд
Разрешён не значит же то обязателен )
0
Don't worry, be happy
17165 / 10049 / 1934
Регистрация: 27.09.2012
Сообщений: 25,035
Записей в блоге: 1
28.06.2017, 19:31 16
Цитата Сообщение от Undisputed Посмотреть сообщение
Разрешён не значит же то обязателен
Если компилятору палки в колеса ставить, то конечно он будет отвечать соответственно.
Цитата Сообщение от Undisputed Посмотреть сообщение
Увы затрудняюсь прочесть текст
Кратко: автоматические именованные объекты,
объявленные в функции или пришедшие как параметры,
в return сначала будут рассматриваться как rvalue,
то бишь перемещаться. Если не получится, то тогда будем копировать.
1
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 19:34 17
Вообще никак не связанно.
Ну почему же?
Если уник пойнтер нельзя копировать, а оптимизацию с перепещением стандарт разрешает но не требует насколько я понимаю, то как иначе в рамках с++ скомпилировать такой код, если не заинлайнить его?
0
Don't worry, be happy
17165 / 10049 / 1934
Регистрация: 27.09.2012
Сообщений: 25,035
Записей в блоге: 1
28.06.2017, 19:39 18
Цитата Сообщение от Undisputed Посмотреть сообщение
то как иначе в рамках с++ скомпилировать такой код

Сначала проверяется возможность перемещения.
Если переместить можно - перемещаем.
Что здесь не понятного?

Добавлено через 51 секунду
Цитата Сообщение от Undisputed Посмотреть сообщение
если не заинлайнить его?
inline никак не поможет. Сначала будет проверена семантика.
Если она не соблюдена, то никакие инлайны не прокатят.
1
Эксперт С++
8426 / 4099 / 894
Регистрация: 15.11.2014
Сообщений: 9,200
28.06.2017, 19:44 19
Цитата Сообщение от Undisputed Посмотреть сообщение
Ну почему же?
любые оптимизации всегда ортогональны синтаксису языка.
компилятор сначала проверяет синтаксис.
и только потом пытается оптимизировать.

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

поэтому не важно, RVO/NRVO там, или inline во все поля.
нельзя скопировать объект, для которого был запрещен конструктор копии.


в случая с юник_птр, компиляция прошла успешно,
потому что для него сработал разрешенный конструктор перемещения
(который в последствии компилятор так же может оптимизировать.
но лишь в последствии. уже позже проверки синтаксиса)
1
749 / 352 / 72
Регистрация: 10.06.2014
Сообщений: 2,371
28.06.2017, 19:48 20
Croessmah, hoggy,
Ясно, спасибо. О семантике я не подумал
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.06.2017, 19:48

Отсутствует std::unique_ptr gcc 4.8.1
всем привет , я в С++ начинающий и возникла проблема не работает std::unique_ptr версия...

Std::unique_ptr virtual метод
#include &lt;iostream&gt; #include &lt;memory&gt; class Base { public: virtual void f1(); // Virtual...

Проблема с умным указателем std::unique_ptr
здравствуйте. есть задание - написать небольшую простенькую игру, где есть базовый класс Unit,...

Не срабатывает move конструктор std::unique_ptr
Всем привет! Битый час не пойму почему в списке захвата компилятор ругается на удаленный копирующий...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.