Перейти к содержимому

Как вернуть вектор из функции c

  • автор:

Как приавильно в функции вернуть vector (C++ Builder)

В билдере работаю не давно, до этого в Дельфях кодил. Объясните как вернуть вектор функцией, которая должна разбить строку по переданному ей делителю?
Ругается на строку возвращения ветора «Undefined symbol ‘prm’«.

vector < AnsiString >explode ( AnsiString str, AnsiString delitel ) <
int len = str. Length ( ) ;
AnsiString search,simbol ;
for ( int i = 1 ; i search = str. SubString ( i, 1 ) ;
if ( search ! = delitel ) <
simbol = simbol + «» + search ;
> else
<
vector < AnsiString >prm ;
prm. push_back ( simbol ) ;
simbol = «» ;
>
>
return prm ;
>

Как вернуть vector из функции: по значению или по ссылке?

Есть функция, создающая каким-то определенным образом экземпляр vector . Вопрос: как вернуть этот экземпляр вызывающему?

Правильное с точки зрения логики и стройности программы решение выглядит так:

std::vectorint> create_vector(const size_t N) std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > 

Тут экземпляр вектора возвращается по значению, что означает потенциальное глубокое копирование локального объекта в контекст вызывающей функции. Сразу возникает сомнение: а что, если вектор огромен — его ж надо будет побайтно перекладывать из одного места в другое? Гораздо “разумнее” было бы написать:

void create_vector(const size_t N, std::vectorint>* v) v->resize(N, 0xDEADC0DE); > 

Тут вектор передается по указателю, и стопроцентно ненужного полного копирования не будет. Но такой код выглядит откровенно плохо.

Сравним скорости работы на векторе длиной 100MB. Например, на компиляторе:

Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn) Target: x86_64-apple-darwin11.3.0 
#include #include std::vectorint> __attribute__((noinline)) create_vector(const size_t N) std::cout  <"by value"  ::endl; std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v = create_vector(N); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_value by_value.cpp && time ./by_value 
0m4.933s 

Теперь по указателю:

#include #include void __attribute__((noinline)) create_vector(const size_t N, std::vectorint>* v) std::cout  <"by pointer"  ::endl; v->resize(N, 0xDEADC0DE); > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v; create_vector(N, &v); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_pointer by_pointer.cpp && time ./by_pointer 
0m4.852s 

Время в обоих случаях одинаково. Получается, что стоит выбрать первый, “красивый” вариант.

Объяснений тут два. Первый, и возможно самый важный — это RVO, Return value optimization. Это когда компилятор догадывается, что создаваемый локальный экземпляр вектора предназначен для возврата из функции, и сразу создает его в контексте вызывающего кода, чтобы потом не копировать туда. Фактически компилятор реализует передачу по ссылке, но неявно, не портя красоту исходного кода. Данный трюк будет работать для любого класса, не обязательно класса из STL.

Но оптимизация — это негарантированная вещь. Но тут есть еще одно подспорье. Стандартные контейнеры STL реализованы так, что при даже при глубоком копировании фактически копируется только небольшая управляющая структура, а сами данные, размещенные в куче, просто перебрасываются указателем, без их фактического перемещения. Тут, конечно, будет небольшое дополнительное копирование, но оно минимально, и возможно на него стоит пойти ради сохранения красивого кода.

Ну а в контексте C++11, где есть семантика перемещения, вообще не будет лишних копирований, если класс “правильно” реализован (что верно для классов из STL).

Мораль: используйте по возможности контейнеры из STL и оставьте оптимизацию компилятору. Иногда, конечно, компилятор ошибается, но таких случаев гораздо меньше, чем наоборот.

Возврат вектора из функции

Как правильно возвращать вектор из функции — возвращать сам вектор, указатель на него или итератор? «Правильность» интересует с точки зрения оптимального использования ресурсов и хорошего стиля программирования.

Отслеживать
371 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков
задан 2 апр 2014 в 17:10
DarkGenius DarkGenius
885 2 2 золотых знака 11 11 серебряных знаков 31 31 бронзовый знак
Передавайте в функцию ссылку на вектор, который вы собираетесь заполнять.
2 апр 2014 в 17:15
А если вектор хранится у меня как поле класса?
2 апр 2014 в 17:19
Темный гений, про RVO — правда
2 апр 2014 в 18:14
@mikillskegg, в данном случае (вектор является полем класса) это неправда.
2 апр 2014 в 19:03

@DarkGenius: Если время жизни вектора — не проблема, конечно возвращайте const ref. Основная проблема C++ и состоит, на мой взгляд, в том, что приходится чересчур много думать об аллокации/деструкции/копировании ресурсов и владении ими. Например, казалось бы, что опасного в конструкции v.push_back(v.back()); ?

5 апр 2014 в 14:30

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Давайте-ка я суммирую дискуссию в комментариях здесь.

Классическим методом является передача пустого вектора по ссылке в функцию, с тем чтобы функция его заполнила.

Затем, если вы уверены, что время жизни вектора, который вы передаёте, достаточно велико (например, вектор является полем класса), то вы можете возвращать ссылку на него. Внимание! При этом вы вводите потенциально опасную зависимость: если сам объект умрёт, ссылка на вектор тоже перестанет быт валидной! Сам объект не может знать, как его используют, и не является ли он, например, временным.

Затем, вы вполне можете вернуть вектор по значению, особенно если вы конструируете его на стеке в самой функции (и значит, не можете вернуть ссылку на него). Это кажется излишним копированием, но на самом деле оптимизатор часто может убрать ненужное копирование используя RVO/NRVO. (Вот ссылкf про это: NRVO in Visual C++ 2005). Тем не менее, иногда эта техника может всё же ведёт к копированию (например, потому, что оптимизатор не волшебник) и показывает плохие результаты.

И ещё: я бы не советовал возвращать итератор. Итераторы в C++ — ещё более хрупкая вещь, чем ссылки: любой чих в сторону вектора может его инвалидировать.

Как вернуть вектор из функции c

Загрузка. Пожалуйста,
подождите.

Здравствуйте, Гость ( Вход | Регистрация | Что даёт регистрация на форуме? )

Дата 30.11.2008, 12:19 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 248
Регистрация: 1.10.2008

Репутация: нет
Всего: нет

Есть два вектора.

Код
#include
Код
vector n1vector;
vector n2vector;

Далее в функции Func1 происходит изменение вектора n1vector (например добавляются новые элементы), а затем из функции возвращается n1vector (что — то типа: return n1vector)
Что — бы работало так: n2vector = Func1();
Тоесть n2vector = n1vector

Вопрос. Какой тип должна иметь функция, для возвращения вектора:

Код
тип Func1()
// действия с вектором n1vector
>

И вообще возможно — ли сделать, то, что я описал выше!?

И еще по теме.
Можно — ли сделать так:

Код
тип Func1(КАКОЙ ЗДЕСЬ ТИП АРГУМЕНТА ПЕРЕМЕННОЙ)
>
n2vector = Func1(n1vector);

Аргумент функции, тоесть, переменная, какой тип она должна иметь, чтобы принять вектор!?

Это сообщение отредактировал(а) freshAngel — 30.11.2008, 12:23

Дата 30.11.2008, 12:31 (ссылка) | (нет голосов) Загрузка .

а ты мне нравишься

Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20

Код
void GetTwoVectors( vector& n1vector, vector& n2vector )
n1vector.push_back(1);
n2vector.push_back(2);
>

Это сообщение отредактировал(а) Artemon — 30.11.2008, 12:32

Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru

Дата 30.11.2008, 15:47 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 248
Регистрация: 1.10.2008

Репутация: нет
Всего: нет

Artemon
Спасибо.
Попробую!

Еще момент, просто у меня данная функция Func1() находится в классе.
В файле, например unit5.cpp

А вызываю я ее в другом *.cpp, естественно описав так:

Код
vClass vC;

Сама функция, как я уже говорил описана и находится в классе (unit5.cpp)
Вызываю ее, например в unit2.cpp

Код
vector n1vector;
vector n2vector;
vC.Func1(n1vector,n2vector);

Найдутся эти переменные (n1vector,n2vector) если эту функцию вызвать из другого *.cpp

Дата 1.12.2008, 05:02 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 554
Регистрация: 31.7.2007
Где: Россия, Омск

Репутация: нет
Всего: 9

Если ты их объявишь в хедере и подключишь этот хедер к другому цпп-шнику, то найдутся

«Звонким вереском скроются наши следы, и не вспомнят о них. Кто поверит нам, рыцарям павшей звезды из отвергнутых книг? Пусть в узоре времен ни стихов. ни имен, но напомнит забывшим их полуночный крик.» Тэм Гринхилл
«Ужели суслик твоего коварства нагадит в плов доверья моего?». Л.Филатов

Дата 1.12.2008, 07:39 (ссылка) | (нет голосов) Загрузка .

а ты мне нравишься

Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20

Если все как ты написал, то найдется, но только не забудь и во 2-й файл вставить #include

Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru

Дата 1.12.2008, 08:41 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306

Цитата(Artemon @ 1.12.2008, 07:39 )
Если все как ты написал, то найдется, но только не забудь и во 2-й файл вставить #include

в таком случае не забываем напоминать использование области видимости std
а по сабжу можно помимо передачи параметров по ссылке — вернуть к примеру структуру из двух элементов из функции или даже массив векторов

Дата 1.12.2008, 10:17 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15

Как вариант:

Код
std::vector Func (std::vector Z)
std::vector X (0);
for(unsigned int count=0; count X.push_back(Z[count]*2);
return X;
>
Код
n1vector=Func(n2vector);

Правда такой вариант требует вспомогательной переменной.

На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) — крупнейший в рунете сборник материалов по Дельфи
  • FAQ раздела лежит здесь!

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »

[ Время генерации скрипта: 0.1307 ] [ Использовано запросов: 21 ] [ GZIP включён ]

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *