Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, sci_reseacher, Вы писали:
_>>Можно ли передавать ссылку на вектор, созданный локально? U>нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен
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 в приведенной цитате понимается неявно созданный автоматический объект, который в приведенном случае создаваться не будет, а значит-таки ссылка будет невалидной после завершения функции (как я и думал раньше, до того, как наткнуться на эти дурацкие плохопрописанные исключения с константными ссылками). извиняюсь, если ввел в заблуждение.
_>P.S. другими словами будет ли метод getX правильно работать? Почему?
Метод getX будет таки правильно работать. А вот то, что пользуется этим методом вряд ли. Разве что, в вызывающем кода в lvalue будет не ссылка, а собственный объект vector<float>, тогда может отработает какой-нить operator= или какая-нить move-семантика, и все создастся.
Здравствуйте, sci_reseacher, Вы писали:
_>Можно ли передавать ссылку на вектор, созданный локально?
нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, _hum_, Вы писали:
__>>и в чем несовпадение?
W>Недостаточно дать переменной имя tmp чтобы она стала считаться тем самым «temporary object» из цитаты
Здравствуйте, 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) оторвать указатель и размер от хранилища, которое владеет памятью
Здравствуйте, 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 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> является индексный доступ, поэтому можно в базовом классе вместо
Это незначительный проигрыш в скорости, но без потерь в памяти. Если в этой иерархии у вас не планируется третий класс, элементы которого будут хранится в контейнере не допускающим индексный доступ, то на этом можно остановится.
Здравствуйте, uzhas, Вы писали:
U>или обратись к Стандарту
Не наш случай. Сей адепт интернет-толкований и научного тыка по компиляторам стандарт не признает.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
_>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'ов копировать в вектор? Можно же просто возвращать два указателя, в качестве итераторов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, sci_reseacher, Вы писали:
_>>Можно ли передавать ссылку на вектор, созданный локально? U>нельзя, т.к. при выходе из метода объект "vector<float> tmp" уже будет уничтожен
А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?
Здравствуйте, sci_reseacher, Вы писали:
_>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?
Зачем? Что ты хочешь добиться? Почему не устраивает возврат по значению, как делает нижеприведённый getVector, а хочется что-то вроде нерабочего getX?
_>что-то типа сделать? _>
_>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *?
зачем вам ссылка нужна? какая задача? возвращайте по значению
Здравствуйте, watchmaker, Вы писали:
_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *? W>Зачем? Что ты хочешь добиться? Почему не устраивает возврат по значению, как делает нижеприведённый getVector, а хочется что-то вроде нерабочего getX?
Здравствуйте, 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;
__>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
Здравствуйте, 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> — одинаковые типы?
Здравствуйте, 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 ]
Здравствуйте, 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.
Здравствуйте, 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 разрушается, как и положено
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, sci_reseacher, Вы писали:
_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *? U>зачем вам ссылка нужна? какая задача? возвращайте по значению
U>вот так: U>
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, sci_reseacher, Вы писали:
_>>А как можно вернуть ссылку на std::vector<float> в данной ситуации, когда имеется float *? U>зачем вам ссылка нужна? какая задача? возвращайте по значению
U>вот так: U>
_>P.S. другими словами будет ли метод getX правильно работать? Почему?
Мало того что дико выглядит, так и еще и работать не будет, но это на самом деле к счастью.
Время жизни твоего вектора ограничено временем жизни внутри функции. На что ты хочешь получить ссылку по окончании работы getX? Там же нет ничего, tmp будет гарантированно удален.
Второе замечание, прикинь что твой getX() сидит внутри большого цикла, вместо ожидаемой передачи ссылки на временный буфер, ты каждый раз его будешь строить.
Если тебе нужен временный буфер, то почему его не объявить в struct A?
В основном вектора будут большие, метод getX будет вызываться не часто, планируется использовать только по ссылке возвращаемое значение:
const vector<T> & w = d.getX();
Кроме того, внутри объекта класса решается какого размера вектор и какие значения он будет хранить.
Поэтому остановлюсь на варианте с возвратом вектора vector<T>.
U>тут возможны альтернативы. U>нужно оценить, насколько негативно в плане производительности, будет возврат вектора по значению. сколько там элементов ? как часто зовется ?
Откуда такие сложности на пустом месте, интерфейсы, абстрактные классы, наследования, перегрузка, куча классов, если задача решается напрямую без академических извратов.
Здравствуйте, sci_reseacher, Вы писали:
_>P.S. другими словами будет ли метод getX правильно работать?
Да, он будет правильно работать. Он будет создавать такие проблемы, которые вы будете месяц искать по всей программе.
_>Почему?
Потому что vector состоит из управляющей структуры и массива значений. Управляющую структуру вы создаете на стеке. А это значит, что после выхода из функции, эта память станет свободным местом на стеке и по мере надобности будет переиспользованна, а ее предыдущее содержимое перетерто. Причем произойдет это не сразу, а когда стек дотянется до этого места.
Здравствуйте, peterbes, Вы писали:
P>Здравствуйте, uzhas, Вы писали:
P>Откуда такие сложности на пустом месте, интерфейсы, абстрактные классы, наследования, перегрузка, куча классов, если задача решается напрямую без академических извратов.
в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.
удобнее всего вернуть ссылку:
const vector<T>& read(){ ... }
т.к. далее работать с классом проще.
P.S. "академические навороты" нужны чтобы "застолбить" единый интерфейс
Здравствуйте, sci_reseacher, Вы писали:
_>const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?
У тебя везде делается лишняя копия.
Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, sci_reseacher, Вы писали:
_>>const vector<float> & w = d.getX(); // только вот здесь для D d нет ли лишней копии вектора? всегда работает return value optimization?
TB>У тебя везде делается лишняя копия. TB>Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.
а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать
TB>>Используй ArrayView. И вместо хранения пары float*, size тоже храни ArrayView.
_>а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать _>
_>const std::vector<T> &
_>
Опять же встречный вопрос: «кому требуется»? Концепция view как раз и подразумевает, что больше никому этот вектор не будет нужен, а возвращаться будет сам view. Соответственно, специализированный наследник сможет сам сконструировать view из своих данных (хоть из вектора, хоть из указателя).
То есть использование view позволяет один раз зафиксировать, что невладеющий доступ к массивам или строчкам в программе будет осуществляться через этот тип, а после этого дилеммы об возвращении const vector<int>& уже не возникнет, потому что в нём и не будет надобности.
_>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.
В чём разница, в первом вопросе этого не было, но было копирование.
Да и хрен с ним, а причем тут vector, который у вас возвращался дичайшим никогда невозвратным образом? Тогда берите слайсы над байтовым массивом и работайте напрямую, возвращая клиенту косвенные индексы
_>P.S. "академические навороты" нужны чтобы "застолбить" единый интерфейс
Здравствуйте, sci_reseacher, Вы писали:
_>а можно по сути разъяснить, как концепция "ArrayView" позволяет не делать лишней копии в указанной ситуации, когда требуется возвращать _>
_>const std::vector<T> &
_>
Потому что тебе не нужно возвращать ссылку на вектор. Тебе надо возвращать ArrayView. Тебе же нужно только что? Количество элементов и доступ к элементам. И всё. И этот ArrayView тебе это предоставил. Но надо, конечно, понимать, что время жизни ArrayView должно быть меньше, чем у вектора. Например, возвращать ArrayView на участок вектора, только что созданного на стеке — это очень плохо.
Смысл в том, что ArrayView можно построить на векторе без переголовы, а наоборот — нельзя.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, sci_reseacher, Вы писали:
_>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.
А что мешает доставать float* из вектора просто?
Зачем хранить две идентичные копии данных?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, sci_reseacher, Вы писали:
_>>в одном классе мне нужен std::vector<T>, в другом T*, т.к. это две разные реализации класса, работающие на разных устройствах --- а пользователь их может выбирать.
E>А что мешает доставать float* из вектора просто? E>Зачем хранить две идентичные копии данных?
Технологии, используемые в классе с полем T* не могут работать с vector<T> и предоставляют для чтения из некоторой области памяти T* ...
Появилась необходимость в классе 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'ов копировать в вектор? Можно же просто возвращать два указателя, в качестве итераторов?
_>Появилась необходимость в классе B, который использует совсем другие технологии расчета и хранения данных (с std::vector не работает), _>но предоставляет указатель float * для обращения к непрерывному участку памяти. Хотелось бы не меняя интерфейс и логику
Здравствуйте, sci_reseacher, Вы писали:
_>Технологии, используемые в классе с полем T* не могут работать с vector<T> и предоставляют для чтения из некоторой области памяти T* ...
То есть данными владеют "технологии"? Или ты им буфер предоставляешь?
18.05.16 12:10: Удалено модератором из 'C/C++'.
18.05.16 12:10: Восстановлено модератором.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, sci_reseacher, Вы писали:
_>>Появилась необходимость в классе B, который использует совсем другие технологии расчета и хранения данных (с std::vector не работает), _>>но предоставляет указатель float * для обращения к непрерывному участку памяти. Хотелось бы не меняя интерфейс и логику
J>Переделай интерфейс на array_view.
имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, sci_reseacher, Вы писали:
_>>имеется ввиду вот эта обертка ? или есть еще какой-то wrapper?
J>Да, эта вполне подойдет. А в следующем стандарте или через один будет встроенный std::array_view
если уж переделывать интерфейс базового класса, то а вот я не пойму: чем же будет лучше возвращать array_view<T>, а не T*?
float* getX(){ };
P.S. извиняюсь, не знаю как удалить сообщение, все, понял ... интерфейс вектора там повторяется и модули работающие с редактируемым классом не нужно править
вот здесь теперь можно быть уверенным, что всегда по ссылке ссылкам 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
Здравствуйте, sci_reseacher, Вы писали:
_>вот здесь теперь можно быть уверенным, что всегда по ссылке ссылкам ref_a, ref_b ... будет доступен актуальный внутренний "array" на чтение без лишних "телодвижений" (копирования приводящего к расходу памяти и времени)?
Да. И нет необходимости создавать константные ссылки, храни их по значению просто.
Здравствуйте, Ops, Вы писали:
Ops>Здравствуйте, uzhas, Вы писали:
U>>или обратись к Стандарту Ops>Не наш случай. Сей адепт интернет-толкований и научного тыка по компиляторам стандарт не признает.
я стандарт избегаю, потому что он написан скорее языком для разработчиков компиляторов, чем для простых пользователей. к тому же очень много исключений, замечаний, нюансов, в которых приходится кропотливо разбираться.
в этом плане ресурс cpp.reference, по-моему, делает хорошее дело — пытается стандарт изложить человеческим языком. другое дело, что у них не всегда это корректно получается сделать.
Здравствуйте, 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();
}
};