хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 01:13
Оценка:
Вот такое дело. Допустим у класса storage есть функция fetch_data, которая возвращает объекты типа data по запросу:
data storage::fetch_data(string const & request);

Пока что data возвращается по значению. Но в большинстве случаев оказывается, что можно было бы возвратить и ссылку на data, сохраненный в storage:
data const & storage::fetch_data(string const & request);

И это было бы гораздо эффективнее текущей версии, так как не надо делать копию data.

Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
Re: хитрый возврат объекта из функции
От: Ops Россия  
Дата: 26.01.11 01:27
Оценка:
Здравствуйте, l33thaxor, Вы писали:

L>Вот такое дело. Допустим у класса storage есть функция fetch_data, которая возвращает объекты типа data по запросу:

L>
L>data storage::fetch_data(string const & request);
L>

L>Пока что data возвращается по значению. Но в большинстве случаев оказывается, что можно было бы возвратить и ссылку на data, сохраненный в storage:
L>
L>data const & storage::fetch_data(string const & request);
L>

L>И это было бы гораздо эффективнее текущей версии, так как не надо делать копию data.

L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?


shared_ptr подойдет?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 01:30
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>shared_ptr подойдет?


Каким образом? В storage объекты хранятся не ввиде shared_ptr.
Re[3]: хитрый возврат объекта из функции
От: Ops Россия  
Дата: 26.01.11 01:36
Оценка:
Здравствуйте, l33thaxor, Вы писали:

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


Ops>>shared_ptr подойдет?


L>Каким образом? В storage объекты хранятся не ввиде shared_ptr.


http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/sp_techniques.html#static
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[4]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 01:44
Оценка:
Здравствуйте, Ops, Вы писали:

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


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


Ops>>>shared_ptr подойдет?


L>>Каким образом? В storage объекты хранятся не ввиде shared_ptr.


Ops>http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/sp_techniques.html#static


В этом случае, когда storage создает новый объект, его прийдется выделять на хипе, а хотелось бы обойтись стеком. Да и shared_ptr со своим deleter'ом выглядить как то тяжеловато тоже. Больше никаких нет вариантов?
Re[5]: хитрый возврат объекта из функции
От: Ops Россия  
Дата: 26.01.11 02:09
Оценка:
Здравствуйте, l33thaxor, Вы писали:

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


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


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


Ops>>>>shared_ptr подойдет?


L>>>Каким образом? В storage объекты хранятся не ввиде shared_ptr.


Ops>>http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/sp_techniques.html#static


L>В этом случае, когда storage создает новый объект, его прийдется выделять на хипе, а хотелось бы обойтись стеком. Да и shared_ptr со своим deleter'ом выглядить как то тяжеловато тоже. Больше никаких нет вариантов?


Ну так все зависит от того, насколько тяжелые объекты и как потом с ними работают. А вместо выделения в хипе можно использовать пул для этих объектов, или даже просто placement new — тут все от многопоточности зависит.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: хитрый возврат объекта из функции
От: _nn_  
Дата: 26.01.11 10:10
Оценка:
Здравствуйте, l33thaxor, Вы писали:

Имеется возможность произвести move ?
Возможно это может будет эффективней всего.

С++0х ждать для move не обязательно, можно его реализовать вручную как в std::auto_ptr делается.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: хитрый возврат объекта из функции
От: Pavel Dvorkin Россия  
Дата: 26.01.11 11:10
Оценка: 1 (1)
Здравствуйте, l33thaxor, Вы писали:

L>В этом случае, когда storage создает новый объект, его прийдется выделять на хипе, а хотелось бы обойтись стеком.


Ну вообще-то вернуть хоть ссылку, хоть указатель на объект, созданный на стеке внутри функции, вне ее — это никуда не годится.

Вопрос — что значит "создает новый объект" ? Один раз вызвали, не нашел, создал. Второй раз — то же ? Первый созданный объект к этому времени должен еще жить? или же можно его память использовать для второго ? Иными словами, их много может быть или в любой момент только один ? Если один — можно банально глобальную переменную завести.
With best regards
Pavel Dvorkin
Re: хитрый возврат объекта из функции
От: ariets  
Дата: 26.01.11 11:42
Оценка:
Здравствуйте, l33thaxor, Вы писали:

Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?


const data &fetch_data( const std::string &request )
{
 if( is_data( request ) )
 {
  return get_data( request );
 }

 static const data emptyData;
 return emtyData;
}
Re[2]: хитрый возврат объекта из функции
От: Хвост  
Дата: 26.01.11 12:16
Оценка:
Здравствуйте, ariets, Вы писали:

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


A>Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?



A>
...
A> static const data emptyData;
A> return emtyData;
A>}
A>


у вас же переменная static, возвращайте всегда ссылку.
People write code, programming languages don't.
Re[3]: хитрый возврат объекта из функции
От: Хвост  
Дата: 26.01.11 12:19
Оценка:
Здравствуйте, Хвост, Вы писали:

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


упс, я думал вы топикстартер. как удалить сообщение?
People write code, programming languages don't.
Re[2]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 15:29
Оценка:
Здравствуйте, ariets, Вы писали:

A>
A>const data &fetch_data( const std::string &request )
A>{
A> if( is_data( request ) )
A> {
A>  return get_data( request );
A> }

A> static const data emptyData;
A> return emtyData;
A>}
A>


Статический объект не подходит. В этом случае не будет работать даже простейшая последовательность двух вызовов fetch_data:
data const & d1 = fetch_data(r1);
data const & d2 = fetch_data(r2);  // d1 is clobbered
Re[6]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 15:30
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вопрос — что значит "создает новый объект" ? Один раз вызвали, не нашел, создал. Второй раз — то же ? Первый созданный объект к этому времени должен еще жить? или же можно его память использовать для второго ?


Должен жить. Память переиспользовать нельзя.
Re[2]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 15:34
Оценка:
Здравствуйте, _nn_, Вы писали:

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


__>Имеется возможность произвести move ?

__>Возможно это может будет эффективней всего.

__>С++0х ждать для move не обязательно, можно его реализовать вручную как в std::auto_ptr делается.


Непонятно, как мне это поможет. Мне нужно оптимизировать для случая возврата существующего объекта по ссылке. Это fast path. Возврат по значению, когда происходит создание нового объекта и копирование его при возврате из функции, это slow path. Она происходит редко и его оптимизировать не надо.
Re[7]: хитрый возврат объекта из функции
От: Pavel Dvorkin Россия  
Дата: 26.01.11 15:48
Оценка:
Здравствуйте, l33thaxor, Вы писали:

L>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Вопрос — что значит "создает новый объект" ? Один раз вызвали, не нашел, создал. Второй раз — то же ? Первый созданный объект к этому времени должен еще жить? или же можно его память использовать для второго ?


L>Должен жить. Память переиспользовать нельзя.


Тогда я не понимаю, как ты хочешь вернуть данные, расположенные на стеке. Допустим на минуту, что это возможно. Сделать-то как ? Нельзя же описать неопределенное число автоматических переменных.
With best regards
Pavel Dvorkin
Re[8]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 16:27
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

L>>Должен жить. Память переиспользовать нельзя.


PD>Тогда я не понимаю, как ты хочешь вернуть данные, расположенные на стеке. Допустим на минуту, что это возможно. Сделать-то как ? Нельзя же описать неопределенное число автоматических переменных.


Я не хочу вернуть данные на стеке. Вопрос заключался в следующем: если данные уже существуют в storage, то вернуть их так же быстро как по сслыке, если же данных нет, то создать из и вернуть по значению.

На самом деле вот один вариант интерфейса, который удовлетворяет данному требованию. Я не хотел его сразу приводить, думал, что кто-нибудь приведет что-нибудь лучше.
// temp_obj - [in/out] указатель на временный объект, переданный из вызывающей стороны,
// в который будет положен объект data, если нельзя вернуть ссылку и необходимо создать новый объект
data const * storage::fetch_data(data * temp_obj, string const & request) {
    if (data const * existing = retrieve_data(request)) {
        return existing;
    }

    create_data(request).swap(*temp_obj);
    return temp_obj;
}

// вызов
data temp_obj;
data const * fetched = storage.fetch_data(&temp_obj, request);
// работаем с fetched
// при выходе из scope, temp_obj освободит объект, который мог создать fetch_data

Здесь удовлетворены требования по производительности. Но мне этот интерфейс не нравится. Во-первых, вызов fetch_data немного кривой получается. А во-вторых, получается, что fetch_data имеет некоторый неоднозначный side effect.

Можно ли реализовать подобную идею с более приличным интерфейсом.
Re[9]: хитрый возврат объекта из функции
От: Pavel Dvorkin Россия  
Дата: 26.01.11 17:04
Оценка:
Здравствуйте, l33thaxor, Вы писали:

L>Здравствуйте, Pavel Dvorkin, Вы писали:


L>>>Должен жить. Память переиспользовать нельзя.


PD>>Тогда я не понимаю, как ты хочешь вернуть данные, расположенные на стеке. Допустим на минуту, что это возможно. Сделать-то как ? Нельзя же описать неопределенное число автоматических переменных.


L>Я не хочу вернуть данные на стеке. Вопрос заключался в следующем: если данные уже существуют в storage, то вернуть их так же быстро как по сслыке, если же данных нет, то создать из и вернуть по значению.


L>На самом деле вот один вариант интерфейса, который удовлетворяет данному требованию. Я не хотел его сразу приводить, думал, что кто-нибудь приведет что-нибудь лучше.


<skipped>

L>Здесь удовлетворены требования по производительности. Но мне этот интерфейс не нравится. Во-первых, вызов fetch_data немного кривой получается. А во-вторых, получается, что fetch_data имеет некоторый неоднозначный side effect.


L>Можно ли реализовать подобную идею с более приличным интерфейсом.


Честно говоря, мне все это совсем не нравится. Создается какой-то непонятный (и, возможно, ненужный) объект, потом внутри в него пересылают данные из вновь созданного, и все это ради того, чтобы этот объект потом мог сам удалиться на выходе из scope.

Я бы просто сделал. Вернул бы указатель то ли на найденный, то ли на прямо там созданный объект и завел бы еще один параметр, указывающий был ли объект создан или нет. Если нет — delete его и все дела.


data const * storage::fetch_data(string const & request, bool& wasFound) {
    if (data const * existing = retrieve_data(request)) {
        wasFound = true;
        return existing;
    }
    wasFound = false
    return create_data(request)
}

...
bool wasFound;
data const * result = fetch_data(request,wasFound);
// use result
if(!wasFound)
  delete result;


А можно чуть похитрее


class data_and_bool
{
  data* result;
  bool wasFound;
  ~data_and_bool()
  {
    if(!wasFound)
     delete data;
  }
};

data_and_bool storage::fetch_data(string const & request) {
    data_and_bool dab;
    if (data const * existing = retrieve_data(request)) {
        dab.wasFound = true;
        dab.result = existing;
    }
  else {
    dab.wasFound = false;
    dab.result = create_data(request);
}
  return dab;
}

data_and_bool dab = storage::fetch_data(request);
// и пусть деструктор уничтожает данные на выходе из scope, если они были созданы


}


Естественно, не компилировал, так что за возможные ошибки сорри. Считай это псевдокодом.
With best regards
Pavel Dvorkin
Re[10]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 17:43
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я бы просто сделал. Вернул бы указатель то ли на найденный, то ли на прямо там созданный объект и завел бы еще один параметр, указывающий был ли объект создан или нет. Если нет — delete его и все дела.


Такая идея мне в голову приходила, но хотелось бы обойтись без создания объектов на хипе, если можно ограничиться стеком. В том интерфейсе, который я привел (с временным temp_obj), объекты создаются на стеке.

Если бы хип был приемлимым, то я бы выбрал вариант с shared_ptr, который был упомянут в первых ответах.
Re[11]: хитрый возврат объекта из функции
От: Pavel Dvorkin Россия  
Дата: 26.01.11 17:58
Оценка:
Здравствуйте, l33thaxor, Вы писали:

L>Такая идея мне в голову приходила, но хотелось бы обойтись без создания объектов на хипе, если можно ограничиться стеком. В том интерфейсе, который я привел (с временным temp_obj), объекты создаются на стеке.


Хм, а create_data где его создает ?
With best regards
Pavel Dvorkin
Re[12]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 26.01.11 18:38
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


L>>Такая идея мне в голову приходила, но хотелось бы обойтись без создания объектов на хипе, если можно ограничиться стеком. В том интерфейсе, который я привел (с временным temp_obj), объекты создаются на стеке.


PD>Хм, а create_data где его создает ?


На стеке и возвращает по значению.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.