Re: хитрый возврат объекта из функции
От: nhie  
Дата: 26.01.11 19:05
Оценка:
Ну если именно на стеке, и копировать при необходимости, то можно как-то так (компилятором не проверял):

struct result
{
    data* p_existing;
    data copied;
    void set(data* p) { p_existing = p; }
    void set(const data& d) { copied = d; p_existing = 0; }
    data& get() { return (p_existing != 0) ? *p_existing : copied; }
};

void fetch_data(string const & request, result& res)
{
    if (data* existing = retrieve_data(request)) {
        res.set(existing);
    }

    res.set( create_data(request) );
}

void use()
{
    result res;
    fetch_data(request, res);
    res.get().#; // use data, either copied or existing
}
Re[2]: хитрый возврат объекта из функции
От: nhie  
Дата: 26.01.11 19:54
Оценка:
А ещё можно p_existing вместо 0 заменить на &copied, наверное проще будет. Ну и интерфейс подточить по вкусу
Re: хитрый возврат объекта из функции
От: Аноним  
Дата: 26.01.11 22:41
Оценка:
Здравствуйте, 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, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?


Если ты в объекте типа 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 в функцию, по моему мнение,вполне себе ничего.
Только я бы ссылку передавал )
Re: хитрый возврат объекта из функции
От: night beast СССР  
Дата: 27.01.11 05:23
Оценка: 3 (1)
Здравствуйте, l33thaxor, Вы писали:

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


такой вариант потестируй:
#include<memory>

template<typename T>
struct data_factory {

   mutable unsigned char data[100];

   data_factory () {}

   T & create ( T const & src ) const {
       return *( new(data) T(src) );
   }
};

data const & fetch_data( string const & request, data_factory<data> const & tmp = data_factory<data>( ) )
   return tmp.create( 1 );
}
Re[2]: хитрый возврат объекта из функции
От: l33thaxor  
Дата: 27.01.11 07:14
Оценка:
Здравствуйте, night beast, Вы писали:

NB>такой вариант потестируй:

NB>
NB>data const & fetch_data( string const & request, data_factory<data> const & tmp = data_factory<data>( ) )
NB>   return tmp.create( 1 );
NB>}
NB>


Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в 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
}
Re[3]: хитрый возврат объекта из функции
От: night beast СССР  
Дата: 27.01.11 07:26
Оценка:
Здравствуйте, l33thaxor, Вы писали:

NB>>такой вариант потестируй:

NB>>
NB>>data const & fetch_data( string const & request, data_factory<data> const & tmp = data_factory<data>( ) )
NB>>   return tmp.create( 1 );
NB>>}
NB>>


L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:

L>data const & proxy_fetch(string const & request) {
L>    return fetch_data(request);  // бум!
L>}


да.
ссылка живет до конца выражения. вариант:
data const & ref = fetch_data(request);
// use ref

не пройдет.
чтобы работало надо в любом случае или передавать объект/буфер в функцию, или возвращать по значению, или отказаться от стека.
от этого не уйти.
Re[3]: хитрый возврат объекта из функции
От: night beast СССР  
Дата: 27.01.11 07:46
Оценка:
Здравствуйте, l33thaxor, Вы писали:

L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:


забыл еще. в деструкторе фабрики надо деструктор вызывать, есть создание прошло.
Re[3]: хитрый возврат объекта из функции
От: nhie  
Дата: 27.01.11 14:48
Оценка: -1 :)
Здравствуйте, 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;
    }


Но невидимые грабли это жестоко
Re[3]: хитрый возврат объекта из функции
От: nhie  
Дата: 27.01.11 14:53
Оценка: 1 (1)
В конце концов, я бы наверное сделал так, вроде вышло удобно в использовании.

    struct data
    {
        int x, y;
    };

    struct fetcher
    {
        fetcher(string const& request)
        {
            if (false)
            {
                p = (data*)0xBAD; // existing, take from storage
                return;
            }
            d = data(); // copy
            p = &d;
        }

        data d;
        data* p;
        data const* operator->() { return p; }
    };

    void use()
    {
        fetcher f("req");
        f->x;
        fetcher f2("req2");
        f2->y;
    }
Re[3]: хитрый возврат объекта из функции
От: gegMOPO4  
Дата: 27.01.11 21:28
Оценка:
Здравствуйте, l33thaxor, Вы писали:
L>Статический объект не подходит. В этом случае не будет работать даже простейшая последовательность двух вызовов fetch_data:
L>
L>data const & d1 = fetch_data(r1);
L>data const & d2 = fetch_data(r2);  // d1 is clobbered
L>


Заведите статический массив на 10 или 100 элементов и используйте циклически. Для произвольного времени жизни результата не подойдёт, но в этом случае не подойдёт и любой из предложенных методов.
Re: хитрый возврат объекта из функции
От: alexeiz  
Дата: 28.01.11 05:07
Оценка:
Здравствуйте, 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();
   }
};

Тогда fetch_data перепишется как-то так:
ptr_value<data> storage::fetch_data(string const & request) {
    if (data const * existing = retrieve_data(request)) {
        return ptr_value<data>(existing);
    }

    return ptr_value<data>(create_data(request));
}
Re: хитрый возврат объекта из функции
От: testpu  
Дата: 10.02.11 12:48
Оценка:
Здравствуйте, 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, чтобы в в большинстве случаев не делать копирования, а делать только в тех редких случаях, когда приходится?

Как такой вариант?
data const & storage::fetch_data(string const & request, data& outForDataThatWasn'tFound, bool& dataFound )
{
...
   if(found)
   {
       dataFound = true;
       return dataThatWasFound;
   }
   else
   {
      outForDataThatWasn'tFound = newdata;
      dataFound = false;
      return outForDataThatWasn'tFound;
   }      
}
Re: хитрый возврат объекта из функции
От: Velheart Беларусь  
Дата: 10.02.11 17:08
Оценка:
Здравствуйте, l33thaxor, Вы писали:

boost::optional<const data&> storage::fetch_data(string const & request);


Не ?
Re: хитрый возврат объекта из функции
От: sidorov18 США  
Дата: 11.02.11 07:59
Оценка:
Здравствуйте, l33thaxor, Вы писали:

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


уверены, что RVO/NRVO не пройдет?
да и насколько тяжелый data? если там просто данные байт на 64 быстрее будет работать копирование на стеке, чем одно выделение на куче.
Re[3]: хитрый возврат объекта из функции
От: sidorov18 США  
Дата: 11.02.11 08:02
Оценка:
Здравствуйте, l33thaxor, Вы писали:


L>Да, это прикольно. Пока только один недостаток вижу (если считать, что массив в data_factory правельного размера и выровнен): если требуется возвратить data из функции, вызывающей fetch_data, то нужно либо делать копирование либо протаскивать data_factory. Т.е.:


Можно data_factory объявить высоко на стеке. сразу после создания потока.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.