А ещё можно p_existing вместо 0 заменить на &copied, наверное проще будет. Ну и интерфейс подточить по вкусу
Re: хитрый возврат объекта из функции
От:
Аноним
Дата:
26.01.11 22:41
Оценка:
Здравствуйте, l33thaxor, Вы писали:
L>Вот такое дело. Допустим у класса storage есть функция fetch_data, которая возвращает объекты типа data по запросу: L>
L>Пока что data возвращается по значению. Но в большинстве случаев оказывается, что можно было бы возвратить и ссылку на data, сохраненный в storage: L>
L>И это было бы гораздо эффективнее текущей версии, так как не надо делать копию data.
L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
Если ты в объекте типа data который тебе возвращается не будешь ничего менять и вызывать только константные методы, то
почему бы не
const data& ref = storage::fetch_data(string const & request);
ну а если уж бандитизмом заниматся во благо производительности то
const data& ref = storage::fetch_data(string const & request);
data& ref2 = const_cast<data&>(ref);
Хотя приведенный тобой вариант с передачей указателя на объект типа data в функцию, по моему мнение,вполне себе ничего.
Только я бы ссылку передавал )
Здравствуйте, l33thaxor, Вы писали:
L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:
data const & proxy_fetch(string const & request) {
return fetch_data(request); // бум!
}
data proxy_fetch(string const & request) {
return fetch_data(request); // OK
}
data const & proxy_fetch(string const & request, data_factory<data> const & tmp = data_factory<data>())
{
return fetch_data(request, tmp); // OK
}
L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:
data const & ref = fetch_data(request);
// use ref
не пройдет.
чтобы работало надо в любом случае или передавать объект/буфер в функцию, или возвращать по значению, или отказаться от стека.
от этого не уйти.
Здравствуйте, l33thaxor, Вы писали:
L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:
забыл еще. в деструкторе фабрики надо деструктор вызывать, есть создание прошло.
Здравствуйте, l33thaxor, Вы писали:
L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:
А, так вам нужно "прикольно", что ж вы сразу-то не сказали Имхо, фокус с аргумент по умолчанию действительно прикольный, но реально такой код я бы использовать не стал: невидимый объект, дохнущий по окончанию full expression — отлично спрятанные грабли... Плюс нарушение стандарта на тему изменения temporaries (mutable это конечно ловко, но это же хак). Но если уж сильно хочется использовать этот вариант, то почему просто не передавать data() как аргумент по умолчанию и делать const_cast<data> — стандарт в обоих случаях нарушается одинаково.
data const & fetch_data( string const & request, data const & tmp = data() )
{
data* p = const_cast<data*>(&tmp);
return tmp;
}
Здравствуйте, l33thaxor, Вы писали: L>Статический объект не подходит. В этом случае не будет работать даже простейшая последовательность двух вызовов fetch_data: L>
Заведите статический массив на 10 или 100 элементов и используйте циклически. Для произвольного времени жизни результата не подойдёт, но в этом случае не подойдёт и любой из предложенных методов.
Здравствуйте, l33thaxor, Вы писали:
L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
Можно попробовать создать variant класс, который будет содержать либо ссылку (указатель) на объект либо копию объекта data.
template <typename T>
class ptr_value : boost::variant<T, const T *>
{
private:
typedef boost::variant<T, const T *> base_t;
struct value_visitor : boost::static_visitor<const T *>
{
const T * operator()(const T & val) const
{
return &val;
}
const T * operator()(const T * ptr) const
{
return ptr;
}
};
const T * get_ptr() const
{
return boost::apply_visitor(value_visitor(), static_cast<const base_t &>(*this));
}
public:
explicit
ptr_value(const T & val)
: base_t(val)
{}
explicit
ptr_value(const T * ptr)
: base_t(ptr)
{}
const T * operator->() const
{
return get_ptr();
}
const T & operator*() const
{
return *get_ptr();
}
};
Здравствуйте, l33thaxor, Вы писали:
L>Вот такое дело. Допустим у класса storage есть функция fetch_data, которая возвращает объекты типа data по запросу: L>
L>Пока что data возвращается по значению. Но в большинстве случаев оказывается, что можно было бы возвратить и ссылку на data, сохраненный в storage: L>
L>И это было бы гораздо эффективнее текущей версии, так как не надо делать копию data.
L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
Как такой вариант?
Здравствуйте, l33thaxor, Вы писали:
L>Но иногда storage не может найти данные по запросу, и он их создаёт. И в этом случае по ссылке возвратить data уже нельзя. Именно поэтому текущая версия fetch_data возвращает по значению. Вопрос: как так возвратить data, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?
уверены, что RVO/NRVO не пройдет?
да и насколько тяжелый data? если там просто данные байт на 64 быстрее будет работать копирование на стеке, чем одно выделение на куче.
L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:
Можно data_factory объявить высоко на стеке. сразу после создания потока.