ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 09:22
Оценка:
Можно ли передавать ссылку на вектор, созданный локально?
struct A
{
    float* X_;
    int size;
    const vector<float> & getX(){
        vector<float> tmp(X_,X_+size);
        return tmp;
    }
    
};

P.S. другими словами будет ли метод getX правильно работать? Почему?
Отредактировано 16.05.2016 9:23 sci_reseacher . Предыдущая версия .
Re: ссылка на локальный вектор
От: Carc Россия http://www.amlpages.com/home.php
Дата: 16.05.16 09:30
Оценка: -4
Здравствуйте, sci_reseacher, Вы писали:

_>Можно ли передавать ссылку на вектор, созданный локально?

_>
_>struct A
_>{
_>    float* X_;
_>    int size;
_>    const vector<float> & getX(){
_>        vector<float> tmp(X_,X_+size);
_>        return tmp;
_>    }
    
_>};
_>

_>P.S. другими словами будет ли метод getX правильно работать? Почему?
Метод getX будет таки правильно работать. А вот то, что пользуется этим методом вряд ли. Разве что, в вызывающем кода в lvalue будет не ссылка, а собственный объект vector<float>, тогда может отработает какой-нить operator= или какая-нить move-семантика, и все создастся.

PS: а еще над лесом летал аист © А потом какой-нить оптимизатор поставит методу getX() соглашение __stdcall и будет вызывающему коду счастье
Aml Pages Home
Re: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 09:37
Оценка: +4
Здравствуйте, sci_reseacher, Вы писали:

_>Можно ли передавать ссылку на вектор, созданный локально?

нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен
Re: ссылка на локальный вектор
От: Igore Россия  
Дата: 16.05.16 10:07
Оценка: 1 (1)
Здравствуйте, sci_reseacher, Вы писали:

_>Можно ли передавать ссылку на вектор, созданный локально?

_>P.S. другими словами будет ли метод getX правильно работать? Почему?
https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
Re[2]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 10:23
Оценка: -8
Здравствуйте, uzhas, Вы писали:

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


_>>Можно ли передавать ссылку на вектор, созданный локально?

U>нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен

на самом деле там есть нюанс:

en.cppreference.com/lifetime
There are two exceptions from that:

The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.



да, на самом деле прав uzhas — под temporary object в приведенной цитате понимается неявно созданный автоматический объект, который в приведенном случае создаваться не будет, а значит-таки ссылка будет невалидной после завершения функции (как я и думал раньше, до того, как наткнуться на эти дурацкие плохопрописанные исключения с константными ссылками). извиняюсь, если ввел в заблуждение.
Отредактировано 16.05.2016 15:51 _hum_ . Предыдущая версия . Еще …
Отредактировано 16.05.2016 11:37 _hum_ . Предыдущая версия .
Re[2]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 10:24
Оценка:
Здравствуйте, uzhas, Вы писали:

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


_>>Можно ли передавать ссылку на вектор, созданный локально?

U>нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен

А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?


что-то типа сделать?
vector<float>  getVector(){
  vector<float> tmp(X_,X_+size);
  return tmp;
}

const vector<float> & getX(){
  return static_cast<const vector<float>&>(getVector());
}
Re[3]: ссылка на локальный вектор
От: watchmaker  
Дата: 16.05.16 10:35
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

Зачем? Что ты хочешь добиться? Почему не устраивает возврат по значению, как делает нижеприведённый getVector, а хочется что-то вроде нерабочего getX?

_>что-то типа сделать?

_>
_>vector<float>  getVector(){
_>  vector<float> tmp(X_,X_+size);
_>  return tmp;
_>}

_>const vector<float> & getX(){
_>  return static_cast<const vector<float>&>(getVector());
_>}
_>
Re[3]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 10:36
Оценка: +1
Здравствуйте, _hum_, Вы писали:

__>на самом деле там есть нюанс:

это не наш случай
Re[4]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 10:39
Оценка:
Здравствуйте, uzhas, Вы писали:

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


__>>на самом деле там есть нюанс:

U>это не наш случай

и в чем несовпадение?
Re[3]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 10:39
Оценка:
Здравствуйте, sci_reseacher, Вы писали:


_>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

зачем вам ссылка нужна? какая задача? возвращайте по значению

вот так:
vector<float> getVector(){
  vector<float> tmp(X_,X_+size);
  return tmp;
}

vector<float> a1 = getVector(); // <-- valid
const vector<float>& a2 = getVector(); // <-- valid as well
Re[5]: ссылка на локальный вектор
От: watchmaker  
Дата: 16.05.16 10:45
Оценка: +4 :)))
Здравствуйте, _hum_, Вы писали:

__>и в чем несовпадение?


Недостаточно дать переменной имя tmp чтобы она стала считаться тем самым «temporary object» из цитаты :)
Re[5]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 10:46
Оценка: -1
Здравствуйте, _hum_, Вы писали:

__>и в чем несовпадение?

в примере ТС нет "temporary object"
Re[4]: ссылка на локальный вектор
От: утпутуук  
Дата: 16.05.16 10:48
Оценка:
Здравствуйте, watchmaker, Вы писали:

_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

W>Зачем? Что ты хочешь добиться? Почему не устраивает возврат по значению, как делает нижеприведённый getVector, а хочется что-то вроде нерабочего getX?

Он явно хочет отстрелить себе ногу
Re[6]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 10:49
Оценка: :))
Здравствуйте, watchmaker, Вы писали:

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


__>>и в чем несовпадение?


W>Недостаточно дать переменной имя tmp чтобы она стала считаться тем самым «temporary object» из цитаты


а можно обоснованно, а не голословно?
Re[7]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 10:54
Оценка:
Здравствуйте, _hum_, Вы писали:


__>а можно обоснованно, а не голословно?


по своей же ссылке читай отсюда: "Temporary objects are created in the following situations"
или обратись к Стандарту
Re[8]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 10:59
Оценка:
Здравствуйте, uzhas, Вы писали:

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



__>>а можно обоснованно, а не голословно?


U>по своей же ссылке читай отсюда: "Temporary objects are created in the following situations"

U>или обратись к Стандарту

замечательно. читаем:

Temporary object lifetime

Temporary objects are created in the following situations: binding a reference to a prvalue, returning a prvalue from a function, conversion that creates a prvalue, lambda expression, (since C++11) copy-initialization that requires conversion of the initializer, list-initialization that constructs an std::initializer_list, (since C++11) and reference-initialization to a different but convertible type or to a bitfield.


при создании const vector<float>& как раз-таки происходит конвертация из vector<float> tmp;
Re[9]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 11:07
Оценка:
Здравствуйте, _hum_, Вы писали:

__>читаем:

__>

__>Temporary object lifetime

__>Temporary objects are created in the following situations: binding a reference to a prvalue, returning a prvalue from a function, conversion that creates a prvalue, lambda expression, (since C++11) copy-initialization that requires conversion of the initializer, list-initialization that constructs an std::initializer_list, (since C++11) and reference-initialization to a different but convertible type or to a bitfield.


читаем внимательнее выделенное: different but convertible type
Re[10]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 11:13
Оценка:
Здравствуйте, uzhas, Вы писали:

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


__>>читаем:

__>>

__>>Temporary object lifetime

__>>Temporary objects are created in the following situations: binding a reference to a prvalue, returning a prvalue from a function, conversion that creates a prvalue, lambda expression, (since C++11) copy-initialization that requires conversion of the initializer, list-initialization that constructs an std::initializer_list, (since C++11) and reference-initialization to a different but convertible type or to a bitfield.


U>читаем внимательнее выделенное: different but convertible type


а что const std::vector<float> и std::vector<float> — одинаковые типы?
Re[10]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 11:19
Оценка:
Здравствуйте, uzhas, Вы писали:

U>читаем внимательнее выделенное: different but convertible type


кстати, вот в этом примере не должен создаваться "temporary object":
struct A {};
struct B : A {};
B b;
const A& a = b;

хотя тут есть "different but convertible type"
скорее всего эта цитата на сайте не очень точна и может ввести в заблуждение
рекомендую обратиться к Стандарту за более точной формулировкой:
начни отсюда, дальше по главам прыгать надо

12.2 Temporary objects [class.temporary]
1 Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning
a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1),
and in some initializations (8.5). [ Note: The lifetime of exception objects is described in 15.1. —end note ]
Even when the creation of the temporary object is unevaluated (Clause 5) or otherwise avoided (12.8), all
the semantic restrictions shall be respected as if the temporary object had been created and later destroyed.
[ Note: This includes accessibility (11) and whether it is deleted, for the constructor selected and for the
destructor. However, in the special case of a function call used as the operand of a decltype-specifier (5.2.2),
no temporary is introduced, so the foregoing does not apply to the prvalue of any such function call. —end
note ]

Re[11]: ссылка на локальный вектор
От: watchmaker  
Дата: 16.05.16 11:22
Оценка:
Здравствуйте, uzhas, Вы писали:

U>рекомендую обратиться к Стандарту за более точной формулировкой:

U>начни отсюда

Да там есть прямым текстом про всю эту ситуацию рассказано:

The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not
extended; the temporary is destroyed at the end of the full-expression in the return statement.

Re[12]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 11:26
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Да там есть прямым текстом про всю эту ситуацию рассказано:


точно, не доскролил туда
хотя это не про наш случай, ведь у нас нет temporary
Отредактировано 16.05.2016 11:31 uzhas . Предыдущая версия . Еще …
Отредактировано 16.05.2016 11:28 uzhas . Предыдущая версия .
Re[12]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 16.05.16 11:27
Оценка:
Здравствуйте, watchmaker, Вы писали:

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


U>>рекомендую обратиться к Стандарту за более точной формулировкой:

U>>начни отсюда

W>Да там есть прямым текстом про всю эту ситуацию рассказано:


W>

W>The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not
W>extended; the temporary is destroyed at the end of the full-expression in the return statement.


watchmaker, это ен означает, что при этом константная ссылка становится невалидной
семантика может быть таковой:
— cоздается копия const vector<float>(tmp) к которой и привязывается ссылка. а исходный объект tmp разрушается, как и положено
Re[13]: ссылка на локальный вектор
От: watchmaker  
Дата: 16.05.16 11:30
Оценка:
Здравствуйте, uzhas, Вы писали:

U>хотя это не про наш слцчай, ведь у нас нет temporary


Так дело в том, что если бы он и был, то это всё равно бы не помогло
Re[14]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 11:33
Оценка: :)
Здравствуйте, watchmaker, Вы писали:

W>Так дело в том, что если бы он и был, то это всё равно бы не помогло


не запутывай нераспутываемое!
Re[4]: ссылка на локальный вектор
От: Current  
Дата: 16.05.16 12:04
Оценка:
Здравствуйте, uzhas, Вы писали:

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



_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

U>зачем вам ссылка нужна? какая задача? возвращайте по значению

U>вот так:

U>
U>vector<float> getVector(){
U>  vector<float> tmp(X_,X_+size);
U>  return tmp;
U>}

U>vector<float> a1 = getVector(); // <-- valid
U>const vector<float>& a2 = getVector(); // <-- valid as well
U>



сколько раз здесь будет копирование объекта?
Re[4]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 12:40
Оценка:
Здравствуйте, uzhas, Вы писали:

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



_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

U>зачем вам ссылка нужна? какая задача? возвращайте по значению

U>вот так:

U>
U>vector<float> getVector(){
U>  vector<float> tmp(X_,X_+size);
U>  return tmp;
U>}

U>vector<float> a1 = getVector(); // <-- valid
U>const vector<float>& a2 = getVector(); // <-- valid as well
U>


нужно сделать наследников D и C класса B, таких, что в одном данные хранятся в std::vector<T>, а в другом классе T* указывает на эти данные.

struct B {
    virtual const vector<float> &  getX() = 0 ;
};


struct C: public B {
    float *X;
    int size;
//    vector<float>  getX(){
//    vector<float> tmp(X,X+size);
//    return tmp;
//    }
};

struct D: public B {
    vector<float> X;
    const vector<float>  & getX(){
        return X;
    }
};


наверное лучший вариант переделать базовый класс

struct B {
    virtual vector<float> getX() = 0 ;
};

struct C: public B {
    float *X;
    int size;

    virtual vector<float> getX(){
        vector<float> tmp(X,X+size);
        return tmp;
    }
};

struct D: public B {
    vector<float> X;
    virtual vector<float>  getX(){
        return X;
    }
};


и использовать так
const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?
Отредактировано 16.05.2016 12:58 sci_reseacher . Предыдущая версия . Еще …
Отредактировано 16.05.2016 12:56 sci_reseacher . Предыдущая версия .
Отредактировано 16.05.2016 12:54 sci_reseacher . Предыдущая версия .
Отредактировано 16.05.2016 12:41 sci_reseacher . Предыдущая версия .
Re[15]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 12:50
Оценка:
Здравствуйте, uzhas, Вы писали:

U>не запутывай нераспутываемое!


кстати, еще один нюанс : http://rsdn.ru/forum/cpp/5797699.1
Автор: uzhas
Дата: 26.09.14
Re[5]: ссылка на локальный вектор
От: uzhas Ниоткуда  
Дата: 16.05.16 13:08
Оценка: 1 (1)
Здравствуйте, sci_reseacher, Вы писали:

_>наверное лучший вариант переделать базовый класс

_>

_>struct B {
_>    virtual vector<float> getX() = 0 ;
_>};

_>struct C: public B {
_>    float *X;
_>    int size;

_>    virtual vector<float> getX(){
_>        vector<float> tmp(X,X+size);
_>        return tmp;
_>    }
_>};

_>struct D: public B {
_>    vector<float> X;
_>    virtual vector<float>  getX(){
_>        return X;
_>    }
_>};
_>


_>и использовать так

_>
_>const vector<float> & w = d.getX(); // только вот здесь нет ли лишней копии вектора?
_>


тут возможны альтернативы.
нужно оценить, насколько негативно в плане производительности, будет возврат вектора по значению. сколько там элементов ? как часто зовется ?
попробую набросать другие варианты:
1)
struct B {
  virtual void getX(vector<float>& result) = 0; <-- при таком подходе можно выиграть на аллокациях, если входной вектор имеет нужный capacity
};


2) оторвать указатель и размер от хранилища, которое владеет памятью
struct B {
  virtual float* getXBegin() = 0;
  virtual size_t getXSize() = 0;
};


3) можно объединить размер и указатель
struct B {
  virtual pair<float*, size_t> getX() = 0;
};


4) либо сделать\заюзать аналог array_view/string_view/string_ref/ link: http://stackoverflow.com/questions/34832090/whats-the-difference-between-span-and-array-view-in-the-gsl-library

5) либо прокинуть функтор для итерации по контейнеру (поэлементно, либо некими группами\страницами)
struct B {
  virtual void processX(std::function<float> f) = 0; //<-- f will be invoked for each "float" value
};


успехов
Re: ссылка на локальный вектор
От: peterbes Россия  
Дата: 16.05.16 13:52
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>Можно ли передавать ссылку на вектор, созданный локально?

_>
_>struct A
_>{
_>    float* X_;
_>    int size;
_>    const vector<float> & getX(){
_>        vector<float> tmp(X_,X_+size);
_>        return tmp;
_>    }
    
_>};
_>

_>P.S. другими словами будет ли метод getX правильно работать? Почему?

Мало того что дико выглядит, так и еще и работать не будет, но это на самом деле к счастью.
Время жизни твоего вектора ограничено временем жизни внутри функции. На что ты хочешь получить ссылку по окончании работы getX? Там же нет ничего, tmp будет гарантированно удален.
Второе замечание, прикинь что твой getX() сидит внутри большого цикла, вместо ожидаемой передачи ссылки на временный буфер, ты каждый раз его будешь строить.
Если тебе нужен временный буфер, то почему его не объявить в struct A?
Re[6]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 14:34
Оценка:
Здравствуйте, uzhas, Вы писали:


В основном вектора будут большие, метод getX будет вызываться не часто, планируется использовать только по ссылке возвращаемое значение:
const vector<T> & w = d.getX();
Кроме того, внутри объекта класса решается какого размера вектор и какие значения он будет хранить.

Поэтому остановлюсь на варианте с возвратом вектора vector<T>.

U>тут возможны альтернативы.

U>нужно оценить, насколько негативно в плане производительности, будет возврат вектора по значению. сколько там элементов ? как часто зовется ?
Re[6]: ссылка на локальный вектор
От: peterbes Россия  
Дата: 16.05.16 15:35
Оценка:
Здравствуйте, uzhas, Вы писали:

Откуда такие сложности на пустом месте, интерфейсы, абстрактные классы, наследования, перегрузка, куча классов, если задача решается напрямую без академических извратов.


 template<class T>
 struct AB
 {
 public:
   AB(){}
   void write( const size_t size, T* pT )
   {
     if (_data.size() < size)_data.resize( size );
     copy( pT, pT + size, _data.begin() );
   }

   const vector<T>& read(){ return _data; }
   size_t get_size(){ return _data.size(); }
 private:
   vector<T> _data;

 };


  float mydata[] = { 1.0f, 2.4f, 3.14f, 2.71f };
  AB<float> sci_buf;
  //sci_buf.w
  sci_buf.write( 4, (float*) mydata );
  auto& Vals = sci_buf.read(); 
 
  Vals[2] = 2.53f; <---- Хлоп! Ошибка компиляции, данные только на чтение
Re: ссылка на локальный вектор
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.05.16 15:38
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>P.S. другими словами будет ли метод getX правильно работать?


Да, он будет правильно работать. Он будет создавать такие проблемы, которые вы будете месяц искать по всей программе.

_>Почему?


Потому что vector состоит из управляющей структуры и массива значений. Управляющую структуру вы создаете на стеке. А это значит, что после выхода из функции, эта память станет свободным местом на стеке и по мере надобности будет переиспользованна, а ее предыдущее содержимое перетерто. Причем произойдет это не сразу, а когда стек дотянется до этого места.
Re[7]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 16:41
Оценка:
Здравствуйте, peterbes, Вы писали:

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


P>Откуда такие сложности на пустом месте, интерфейсы, абстрактные классы, наследования, перегрузка, куча классов, если задача решается напрямую без академических извратов.



P>
P> template<class T>
P> struct AB
P> {
P> public:
P>   AB(){}
P>   void write( const size_t size, T* pT )
P>   {
P>     if (_data.size() < size)_data.resize( size );
P>     copy( pT, pT + size, _data.begin() );
P>   }

P>   const vector<T>& read(){ return _data; }
P>   size_t get_size(){ return _data.size(); }
P> private:
P>   vector<T> _data;

P> };
P>


P>
P>  float mydata[] = { 1.0f, 2.4f, 3.14f, 2.71f };
P>  AB<float> sci_buf;
P>  //sci_buf.w
P>  sci_buf.write( 4, (float*) mydata );
P>  auto& Vals = sci_buf.read(); 
 
P>  Vals[2] = 2.53f; <---- Хлоп! Ошибка компиляции, данные только на чтение
P>



в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.

удобнее всего вернуть ссылку:
const vector<T>& read(){ ... }

т.к. далее работать с классом проще.

P.S. "академические навороты" нужны чтобы "застолбить" единый интерфейс
Отредактировано 16.05.2016 16:42 sci_reseacher . Предыдущая версия .
Re[5]: ссылка на локальный вектор
От: T4r4sB Россия  
Дата: 16.05.16 16:59
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?


У тебя везде делается лишняя копия.
Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 16.05.16 17:14
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


_>>const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?


TB>У тебя везде делается лишняя копия.

TB>Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.

а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать
const std::vector<T> &

а доступно: или контейнер
std::vector<T> w;

или указатель по которому можно читать
T *u;

?
Re[7]: ссылка на локальный вектор
От: watchmaker  
Дата: 16.05.16 17:23
Оценка:
Здравствуйте, sci_reseacher, Вы писали:


TB>>Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.


_>а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать

_>
_>const std::vector<T> &
_>


Опять же встречный вопрос: «кому требуется»? Концепция view как раз и подразумевает, что больше никому этот вектор не будет нужен, а возвращаться будет сам view. Соответственно, специализированный наследник сможет сам сконструировать view из своих данных (хоть из вектора, хоть из указателя).

То есть использование view позволяет один раз зафиксировать, что невладеющий доступ к массивам или строчкам в программе будет осуществляться через этот тип, а после этого дилеммы об возвращении const vector<int>& уже не возникнет, потому что в нём и не будет надобности.
Re[8]: ссылка на локальный вектор
От: peterbes Россия  
Дата: 16.05.16 17:35
Оценка:
_>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.

В чём разница, в первом вопросе этого не было, но было копирование.

Да и хрен с ним, а причем тут vector, который у вас возвращался дичайшим никогда невозвратным образом? Тогда берите слайсы над байтовым массивом и работайте напрямую, возвращая клиенту косвенные индексы

_>P.S. "академические навороты" нужны чтобы "застолбить" единый интерфейс


Можете пояснить?
Re[7]: ссылка на локальный вектор
От: T4r4sB Россия  
Дата: 16.05.16 19:10
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать

_>
_>const std::vector<T> &
_>


Потому что тебе не нужно возвращать ссылку на вектор. Тебе надо возвращать ArrayView. Тебе же нужно только что? Количество элементов и доступ к элементам. И всё. И этот ArrayView тебе это предоставил. Но надо, конечно, понимать, что время жизни ArrayView должно быть меньше, чем у вектора. Например, возвращать ArrayView на участок вектора, только что созданного на стеке — это очень плохо.
Смысл в том, что ArrayView можно построить на векторе без переголовы, а наоборот — нельзя.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[8]: ссылка на локальный вектор
От: Ops Россия  
Дата: 16.05.16 20:52
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>или обратись к Стандарту

Не наш случай. Сей адепт интернет-толкований и научного тыка по компиляторам стандарт не признает.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: ссылка на локальный вектор
От: Erop Россия  
Дата: 17.05.16 04:38
Оценка: +1
Здравствуйте, sci_reseacher, Вы писали:

_>Можно ли передавать ссылку на вектор, созданный локально?

_>
_>struct A
_>{
_>    float* X_;
_>    int size;
_>    const vector<float> & getX(){
_>        vector<float> tmp(X_,X_+size);
_>        return tmp;
_>    }
    
_>};
_>

_>P.S. другими словами будет ли метод getX правильно работать? Почему?
1) А зачем tmp не временный? Можно же так:
struct A
{
    float* X_;
    int size;
    vector<float> getX(){
        return vector<float> tmp(X_,X_+size);
    }
    
_>};

2) Зачем возвращать ссылку? Можно же просто копию, в надежде на RVO, а если объект временным делать нельзя, то NRVO
3) Если С++11 и позже, то возвращаемое значение можно через мув-конструктор получать, что недорого
4) Главное, зачем вообще этот массив float'ов копировать в вектор? Можно же просто возвращать два указателя, в качестве итераторов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: ссылка на локальный вектор
От: Erop Россия  
Дата: 17.05.16 04:53
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.


А что мешает доставать float* из вектора просто?
Зачем хранить две идентичные копии данных?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 17.05.16 06:18
Оценка:
Здравствуйте, Erop, Вы писали:

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


_>>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.


E>А что мешает доставать float* из вектора просто?

E>Зачем хранить две идентичные копии данных?

Технологии, используемые в классе с полем T* не могут работать с vector<T> и предоставляют для чтения из некоторой области памяти T* ...
Отредактировано 17.05.2016 6:21 sci_reseacher . Предыдущая версия .
Re[2]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 17.05.16 07:07
Оценка:
Здравствуйте, Erop, Вы писали:

Задачка такая была.

Есть некоторый класс A который как-то вычисляет (work) значения (например float) некоторого вектора X
struct Base {
    virtual const std::vector<float> & setX() = 0;
};

struct A: public Base {
   std::vector<float> X;
   A(){ X.resize(10,55);}
   void work() { fill( X.begin(), X.end(), 25 );  }
   const std::vector<float> & setX() { return X; }
};

и работать с ним было очень удобно: поставил ссылку на вектор X и читаешь значения когда нужно:
A a;
const std::vector<float> & x = a.setX();
copy( x.begin(), x.end(), ostream_iterator<float>( cout, " "));
a.work();
copy( x.begin(), x.end(), ostream_iterator<float>( cout, " "));




Появилась необходимость в классе B, который использует совсем другие технологии расчета и хранения данных (с std::vector не работает),
но предоставляет указатель float * для обращения к непрерывному участку памяти. Хотелось бы не меняя интерфейс и логику
всех модулей и программ в классе B сделать setX такой же как и в классе A
struct B: public Base {
   float* X;
   int size;
   B(){ /* .. */ }
   void work() { /* hard calc. for X */  }
   const std::vector<float> & setX() { return /* ..*/; }
};


Похоже, что единственный вариант, сделать в B() поле std::vector или в Base его перенести.


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


_
E>1) А зачем tmp не временный? Можно же так:
E>
struct A
E>{
E>    float* X_;
E>    int size;
E>    vector<float> getX(){
E>        return vector<float> tmp(X_,X_+size);
E>    }
    
_>>};
E>

E>2) Зачем возвращать ссылку? Можно же просто копию, в надежде на RVO, а если объект временным делать нельзя, то NRVO
E>3) Если С++11 и позже, то возвращаемое значение можно через мув-конструктор получать, что недорого
E>4) Главное, зачем вообще этот массив float'ов копировать в вектор? Можно же просто возвращать два указателя, в качестве итераторов?
Re[3]: ссылка на локальный вектор
От: jazzer Россия Skype: enerjazzer
Дата: 17.05.16 08:34
Оценка:
Здравствуйте, sci_reseacher, Вы писали:


_>Появилась необходимость в классе B, который использует совсем другие технологии расчета и хранения данных (с std::vector не работает),

_>но предоставляет указатель float * для обращения к непрерывному участку памяти. Хотелось бы не меняя интерфейс и логику

Переделай интерфейс на array_view.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[10]: ссылка на локальный вектор
От: Erop Россия  
Дата: 17.05.16 09:08
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>Технологии, используемые в классе с полем T* не могут работать с vector<T> и предоставляют для чтения из некоторой области памяти T* ...


То есть данными владеют "технологии"? Или ты им буфер предоставляешь?

18.05.16 12:10: Удалено модератором из 'C/C++'.
18.05.16 12:10: Восстановлено модератором.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: ссылка на локальный вектор
От: B0FEE664  
Дата: 17.05.16 10:23
Оценка: 1 (1)
Здравствуйте, sci_reseacher, Вы писали:

_>нужно сделать наследников D и C класса B, таких, что в одном данные хранятся в std::vector<T>, а в другом классе T* указывает на эти данные.

  Скрытый текст
_>
_>struct B {
_>    virtual const vector<float> &  getX() = 0 ;
_>};


_>struct C: public B {
_>    float *X;
_>    int size;
_>//    vector<float>  getX(){
_>//    vector<float> tmp(X,X+size);
_>//    return tmp;
_>//    }
_>};

_>struct D: public B {
_>    vector<float> X;
_>    const vector<float>  & getX(){
_>        return X;
_>    }
_>};
_>

_>наверное лучший вариант переделать базовый класс
_>

_>struct B {
_>    virtual vector<float> getX() = 0 ;
_>};

  Скрытый текст
_>struct C: public B {
_>    float *X;
_>    int size;

_>    virtual vector<float> getX(){
_>        vector<float> tmp(X,X+size);
_>        return tmp;
_>    }
_>};

_>struct D: public B {
_>    vector<float> X;
_>    virtual vector<float>  getX(){
_>        return X;
_>    }
_>};
_>

_>и использовать так
_>
_>const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?
_>


Я сомневаюсь, что это лучший вариант, т.к. это потеря и в скорости, и в расходе памяти.
Смотрите: вам нужно к объектам разной природы предоставить единый интерфейс.
Возвращать vector — значит конвертировать один тип (T*) в другой — std::vector<T>. Это самый тривиальный способ, но есть и другие подходы.
Например, выделить у T* и std::vector<T> общий интерфейс и дать к нему доступ.
Общим специфичным интерфейсом для T* и std::vector<T> является индексный доступ, поэтому можно в базовом классе вместо
struct B
{
    virtual vector<float> getX() = 0 ;
};

отдать вот такой интерфейс:
struct B
{
    virtual float  getElementX(size_t index) = 0 ;
    virtual size_t getSizeX() = 0;
};


Это незначительный проигрыш в скорости, но без потерь в памяти. Если в этой иерархии у вас не планируется третий класс, элементы которого будут хранится в контейнере не допускающим индексный доступ, то на этом можно остановится.
И каждый день — без права на ошибку...
Re[4]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 17.05.16 15:15
Оценка:
Здравствуйте, jazzer, Вы писали:

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



_>>Появилась необходимость в классе B, который использует совсем другие технологии расчета и хранения данных (с std::vector не работает),

_>>но предоставляет указатель float * для обращения к непрерывному участку памяти. Хотелось бы не меняя интерфейс и логику

J>Переделай интерфейс на array_view.


имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?
Re[5]: ссылка на локальный вектор
От: jazzer Россия Skype: enerjazzer
Дата: 17.05.16 15:20
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?


Да, эта вполне подойдет. А в следующем стандарте или через один будет встроенный std::array_view
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 17.05.16 15:26
Оценка:
Здравствуйте, jazzer, Вы писали:

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


_>>имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?


J>Да, эта вполне подойдет. А в следующем стандарте или через один будет встроенный std::array_view


если уж переделывать интерфейс базового класса, то а вот я не пойму: чем же будет лучше возвращать array_view<T>, а не T*?

float* getX(){ };



P.S. извиняюсь, не знаю как удалить сообщение, все, понял ... интерфейс вектора там повторяется и модули работающие с редактируемым классом не нужно править
Отредактировано 17.05.2016 15:35 sci_reseacher . Предыдущая версия .
Re[6]: ссылка на локальный вектор
От: sci_reseacher  
Дата: 18.05.16 06:35
Оценка:
вот здесь теперь можно быть уверенным, что всегда по ссылке ссылкам ref_a, ref_b ... будет доступен актуальный внутренний "array" на чтение без лишних "телодвижений" (копирования приводящего к расходу памяти и времени)?

struct A {
    std::vector<float> X;
    A(){ X.resize(10,5);}
    void work(void) { std::fill(X.begin(),X.end(),6); }
    arv::array_view<float>  getX(){
        return X;
    }
 };

struct B {
    float* X;
    B(){ X = new float[10];}
    void work(void) { for(int i=0; i<10; ++i) X[i] = i; }
    arv::array_view<float>  getX(){
        return {&X[0],10};
    }
 };

struct C {
    std::valarray<float> X;
    C(){ X.resize(5);}
    void work(void) { X += 3.14; }
    arv::array_view<float>  getX(){
        return {&X[0],X.size()};
    }
 };


A a;
const arv::array_view<float> & ref_a = a.getX();

B * b = new B;
const arv::array_view<float> & ref_b = b->getX();




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

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


_>>имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?


J>Да, эта вполне подойдет. А в следующем стандарте или через один будет встроенный std::array_view
Re[7]: ссылка на локальный вектор
От: jazzer Россия Skype: enerjazzer
Дата: 18.05.16 07:11
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>вот здесь теперь можно быть уверенным, что всегда по ссылке ссылкам ref_a, ref_b ... будет доступен актуальный внутренний "array" на чтение без лишних "телодвижений" (копирования приводящего к расходу памяти и времени)?


Да. И нет необходимости создавать константные ссылки, храни их по значению просто.

З.Ы. И не топ-пости
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: ссылка на локальный вектор
От: _hum_ Беларусь  
Дата: 18.05.16 10:27
Оценка:
Здравствуйте, Ops, Вы писали:

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


U>>или обратись к Стандарту

Ops>Не наш случай. Сей адепт интернет-толкований и научного тыка по компиляторам стандарт не признает.

я стандарт избегаю, потому что он написан скорее языком для разработчиков компиляторов, чем для простых пользователей. к тому же очень много исключений, замечаний, нюансов, в которых приходится кропотливо разбираться.
в этом плане ресурс cpp.reference, по-моему, делает хорошее дело — пытается стандарт изложить человеческим языком. другое дело, что у них не всегда это корректно получается сделать.
Re[10]: ссылка на локальный вектор
От: Ops Россия  
Дата: 18.05.16 10:39
Оценка:
Здравствуйте, _hum_, Вы писали:

__>я стандарт избегаю, потому что он написан скорее языком для разработчиков компиляторов, чем для простых пользователей. к тому же очень много исключений, замечаний, нюансов, в которых приходится кропотливо разбираться.

Чего думать? Трясти надо! © Анекдот.
__>в этом плане ресурс cpp.reference, по-моему, делает хорошее дело — пытается стандарт изложить человеческим языком. другое дело, что у них не всегда это корректно получается сделать.
Хорошее, хорошее дело он делает. Но он не первоисточник, и в спорных случаях его мнение 10-е.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[5]: ссылка на локальный вектор
От: Igore Россия  
Дата: 19.05.16 14:47
Оценка:
Здравствуйте, sci_reseacher, Вы писали:

_>>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?

U>>зачем вам ссылка нужна? какая задача? возвращайте по значению
_>нужно сделать наследников D и C класса B, таких, что в одном данные хранятся в std::vector<T>, а в другом классе T* указывает на эти данные.
А нельзя относледовать D от C?

struct B {
    virtual const vector<float> &  getX() = 0 ;
};

struct D: public B {
    vector<float> X;
    const vector<float>& getX(){
    return X;
    }
};

struct C: public D {
    float *X;
    int size;
    void update() {
       X = X.data();
       size = X.size();
    }
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.