David O'Neil Ответов: 2

Самый простой способ возврата из функции без создания копии


Я только начинаю изучать семантику перемещения, и, судя по моему чтению, она полезна только тогда, когда класс 'new- в нем что-то есть. Я что-то упускаю, или это делает его таким, что если я хочу исключить копирование элемента при возвращении из функции, один из способов сделать это-использовать std::unique_ptr? Например, учитывая, что struct:

struct Triangle {
   POINT p1;
   POINT p2;
   POINT p3;
   };


Если я хочу вернуться из функции, которая ее создает, то лучший способ сделать это-сделать что-то вроде следующего:

std:unique_ptr<MouseHelper::Triangle> MouseHelper::makeTrianglePointingDown(int x, int y) {
   //The following is hard coded for the sizes I'm using in the example
   const int halfSize = 5;
   std:unique_ptr<Triangle> t(new Triangle);
   t->p1.x = x-halfSize;
   t->p1.y = y-halfSize-halfSize;

   t->p2.x = x+halfSize;
   t->p2.y = y-halfSize-halfSize;

   t->p3.x = x;
   t->p3.y = y-2;

   return t;
   }


В противном случае, я должен сделать 'Triangle- в класс, и ... new структура внутри этого класса, а затем создать соответствующий конструктор перемещения?

Спасибо!

Что я уже пробовал:

Чтение. И приведенный выше код работает.

2 Ответов

Рейтинг:
15

CPallini

Самый простой способ-вернуть объект по значению, компилятор оптимизирует его (NRVO).
Попробуй

#include <iostream>
using namespace std;

struct Point
{
  int x, y;
};

struct Triangle
{
  Point p1,p2,p3;
  Triangle(){cout << "Triangle ctor" << endl;}
};

Triangle makeTrianglePointingDown(int x, int y)
{
   const int halfSize = 5;

   Triangle t;
   t.p1.x = x-halfSize;
   t.p1.y = y-halfSize-halfSize;

   t.p2.x = x+halfSize;
   t.p2.y = y-halfSize-halfSize;

   t.p3.x = x;
   t.p3.y = y-2;

   return t;
}

int main()
{
  Triangle tpd  = makeTrianglePointingDown(10,10);
  cout << tpd.p1.x << " " << tpd.p1.y << " ";
  cout << tpd.p2.x << " " << tpd.p2.y << " ";
  cout << tpd.p3.x << " " << tpd.p3.y << endl;
}


David O'Neil

Спасибо! В каких случаях компилятор не может использовать NRVO?

Maciej Los

5ed!

Рейтинг:
0

User 6901758

Если вы хотите динамическое выделение памяти, то да unique_ptr может быть решением.
Но даже если вы просто возвращаете переменную локальной структуры функции из функции, это можно сделать без копирования. Функция вызывающего абонента может предварительно выделить пространство стека, и вызываемый абонент просто заполнит это пространство. И этот блок памяти будет использоваться после вызова без копирования.


David O'Neil

Можете ли вы показать пример или указать на сайт, который показывает технику в C++?

Спасибо!

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

Rick York

Я полагаю, что он утверждает, что вы можете передать указатель в функцию следующим образом :

makeTrianglePointingDown( int x, int y, треугольник *pt );

а указатель-это адрес объекта стека от вызывающего объекта :

Треугольник Т;
makeTrianglePointingDown( x, y, &t );

David O'Neil

Вот о чем я догадывался, но это меня не интересовало. Я выполнил слишком много вызовов 'GetClientRect' таким образом... Скучный...

[no name]

Привет! Я имел в виду то же самое, что и в решении № 2. компилятор оптимизирует это за счет работы с одним и тем же блоком памяти в стеке от вызывающего и вызываемого абонента.

David O'Neil

Спасибо!