Используя массивы или станд.:: векторы в C++, каков разрыв производительности?

Ниже приведен пример передачи параметров в документ fxml через пространство имен.

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/null" xmlns:fx="http://javafx.com/fxml/1">
    <BorderPane>
        <center>
            <Label text="$labelText"/>
        </center>
    </BorderPane>
</VBox>

Определить значение External Text для переменной пространства имен labelText:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class NamespaceParameterExampleApplication extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws IOException {
        final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("namespace-parameter-example.fxml"));

        fxmlLoader.getNamespace()
                  .put("labelText", "External Text");

        final Parent root = fxmlLoader.load();

        primaryStage.setTitle("Namespace Parameter Example");
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }
}
197
задан Mihai Limbășan 6 April 2009 в 16:24
поделиться

13 ответов

Используя массивы C++ с new (то есть, с помощью динамических массивов) должен избежаться. Существует проблема, которую необходимо отслеживать размер, и Вы должны удалить их вручную и действительно все сортируете обслуживания.

Используя массивы на стеке также препятствуется, потому что у Вас нет проверки диапазона, и раздавание массива потеряет любую информацию о своем размере (массив к преобразованию указателя). Необходимо использовать boost::array в этом случае, который обертывает массив C++ в маленький класс и обеспечивает size функция и итераторы для итерации по ней.

Теперь станд.:: вектор по сравнению с собственными массивами C++ (взятый из Интернета):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

Примечание: Если Вы выделяете массивы с new и выделяете необъекты класса (как плоскость int) или классы без определяемого пользователем конструктора , и Вы не хотите инициализировать свои элементы первоначально, с помощью new - выделенные массивы могут иметь преимущества производительности, потому что std::vector инициализирует все элементы к значениям по умолчанию (0 для интервала, например) на конструкции (кредиты к @bernie для запоминания меня).

185
ответ дан Johannes Schaub - litb 4 November 2019 в 14:49
поделиться

Иногда массивы действительно лучше, чем векторы. Если Вы всегда управляете набором фиксированной длины объектов, массивы лучше. Рассмотрите следующие фрагменты кода:

int main() {
int v[3];
v[0]=1; v[1]=2;v[2]=3;
int sum;
int starttime=time(NULL);
cout << starttime << endl;
for (int i=0;i<50000;i++)
for (int j=0;j<10000;j++) {
X x(v);
sum+=x.first();
}
int endtime=time(NULL);
cout << endtime << endl;
cout << endtime - starttime << endl;

}

то, где векторная версия X

class X {
vector<int> vec;
public:
X(const vector<int>& v) {vec = v;}
int first() { return vec[0];}
};

и версия массива X:

class X {
int f[3];

public:
X(int a[]) {f[0]=a[0]; f[1]=a[1];f[2]=a[2];}
int first() { return f[0];}
};

желание версии массива основных () будет быстрее, потому что мы избегаем издержек "новых" каждый раз во внутреннем цикле.

(Этот код был отправлен на comp.lang.c ++ мной).

1
ответ дан duli 4 November 2019 в 14:49
поделиться

Я утверждал бы, что первоочередной задачей не является производительность, но безопасность. Можно сделать много ошибок с массивами (рассмотрите изменение размеров, например), где вектор сохранил бы Вас много боли.

1
ответ дан Gabriel Isenberg 4 November 2019 в 14:49
поделиться

Мог бы быть некоторый пограничный случай, где у Вас есть векторный доступ в подставляемой функции в подставляемой функции, куда Вы пошли вне того, что встроит компилятор, и это вызовет вызов функции. Это было бы столь же редко относительно не стоить взволновать о - в целом я соглашусь с litb.

я удивлен, что никто не упомянул, что это все же - не волнуется о производительности, пока это, как не доказывали, было проблемой, затем сравнивает.

1
ответ дан Community 4 November 2019 в 14:49
поделиться

Если Вы не должны динамично корректировать размер, у Вас есть память наверху сохранения способности (один pointer/size_t). Вот именно.

1
ответ дан Greg Rogers 4 November 2019 в 14:49
поделиться

Различие в производительности между этими двумя является очень зависящим от реализации - при сравнении плохо реализованного станд.:: вектор к оптимальной реализации массива, массив победил бы, но изменил бы к лучшему его, и вектор победит...

, пока Вы сравниваете яблоки с яблоками (или и массив и вектор имеют постоянное число элементов, или оба изменены динамично), я думал бы, что различие в производительности незначительно, пока Вы применяете, получил практику кодирования STL. Не забывайте, что использование стандартных контейнеров C++ также позволяет Вам использовать предварительно прокрученные алгоритмы, которые являются частью стандартной библиотеки C++, и большинство из них, вероятно, будет лучше работать, чем средняя реализация того же алгоритма, который Вы создаете сами.

Однако по моему скромному мнению, векторные победы в сценарии отладки с STL отладки, поскольку большинство реализаций STL с надлежащим режимом отладки может, по крайней мере, highlight/cathc типичные ошибки, сделанные людьми при работе со стандартными контейнерами.

, О, и не забывают, что массив и вектор совместно используют то же расположение памяти, таким образом, можно использовать векторы для передачи данных наследию C или коду C++, который ожидает основные массивы. Следует иметь в виду, что большинство ставок выключено в том сценарии, тем не менее, и Вы имеете дело с необработанной памятью снова.

2
ответ дан Timo Geusch 4 November 2019 в 14:49
поделиться

При компиляции программного обеспечения в режиме отладки много компиляторов не встроят функции средства доступа вектора. Это сделает stl векторную реализацию намного медленнее при обстоятельствах, где производительность является проблемой. Это также сделает код легче отладить, так как Вы видите в отладчике, сколько памяти было выделено.

В оптимизированном режиме, я ожидал бы, что stl вектор приблизится к эффективности массива. Это, так как многие векторные методы теперь встраиваются.

3
ответ дан 4 November 2019 в 14:49
поделиться

STL является в большой степени оптимизированной библиотекой. На самом деле даже предлагается использовать STL в играх, где высокая производительность могла бы быть необходима. Массивы слишком подвержены ошибкам, чтобы использоваться в повседневных задачах. Сегодняшние компиляторы также очень умны и могут действительно произвести превосходный код с STL. Если Вы знаете то, что Вы делаете, STL может обычно обеспечивать необходимую производительность. Например, путем инициализации векторов к необходимому размеру (если Вы знаете от запуска), можно в основном достигнуть производительности массива. Однако могли бы быть случаи, где Вам все еще нужны массивы. При взаимодействии через интерфейс с низкоуровневым кодом (т.е. блок) или старые библиотеки, которые требуют массивов, Вы не могли бы быть в состоянии использовать векторы.

5
ответ дан Mehrdad Afshari 4 November 2019 в 14:49
поделиться

Пойдите с STL. Нет никакой потери производительности. Алгоритмы очень эффективны, и они делают хорошее задание обработки видов деталей, о которых большинство из нас не думало бы.

6
ответ дан John D. Cook 4 November 2019 в 14:49
поделиться

Ответить на что-то сказанный Mehrdad:

Однако могли бы быть случаи, где Вам все еще нужны массивы. При взаимодействии через интерфейс с низкоуровневым кодом (т.е. блок) или старые библиотеки, которые требуют массивов, Вы не могли бы быть в состоянии использовать векторы.

Не верный вообще. Векторы ухудшаются приятно в массивы/указатели, если Вы используете:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

Это работает на все основные реализации STL. В следующем стандарте это потребуется, чтобы работать (даже при том, что это делает очень хорошо сегодня).

25
ответ дан Community 4 November 2019 в 14:49
поделиться

Векторы являются массивами под капотом. Производительность является тем же.

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

, Поскольку вектор заполняется, он изменит размеры себя, и это может подразумевать, новое распределение массива, сопровождаемый n копируют конструкторов, сопровождаемых приблизительно n вызовы деструктора, сопровождаемый массивом удаляют.

, Если Ваш создавать/разрушать является дорогим, Вы - очень более обеспеченное создание вектора корректный размер для начала.

существует простой способ продемонстрировать это. Создайте простой класс, который показывает, когда он создан/уничтожен/скопирован/присвоен. Создайте вектор этих вещей и начните продвигать их на бэкэнде вектора. Когда вектор заполнится, будет каскад действия, поскольку вектор изменяет размеры. Тогда попробуйте его снова вектором, измеренным к ожидаемому числу элементов. Вы будете видеть различие.

30
ответ дан EvilTeach 4 November 2019 в 14:49
поделиться

Преамбула для людей микрооптимизатора

Помнит:

"Программисты тратят впустую огромное количество времени, думающее об или вызывающее беспокойство о, скорость некритических частей их программ, и эти попытки эффективности на самом деле оказывают сильное негативное влияние, когда отладку и обслуживание рассматривают. Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла. все же мы не должны отказываться от наших возможностей в этом критические 3%".

(Благодаря метаморфоза для полной кавычки)

не используют массив C вместо вектора (или безотносительно) просто, потому что Вы полагаете, что это быстрее, поскольку это, как предполагается, низшего уровня. Вы были бы неправы.

Использование вектором по умолчанию (или безопасный контейнер, адаптированный к Вашей потребности), и затем если Ваш профилировщик говорит, это - проблема, посмотрите, можно ли оптимизировать его, или при помощи лучшего алгоритма или при помощи изменяющегося контейнера.

Это сказало, мы можем вернуться к исходному вопросу.

Статический / Динамический массив?

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

, В целом, это падает на две категории:

Динамические массивы

Используя указатель на массив malloc-ed/new-ed будут на высоте с такой скоростью, как станд.:: векторная версия, и намного менее безопасный (см. сообщение litb ).

Так используют станд.:: вектор.

Статические массивы

Используя статический массив будут на высоте:

Так используют станд.:: массив .

Неинициализированная память

Иногда, с помощью vector вместо необработанного буфера несет видимые расходы, потому что эти vector инициализирует буфер в конструкции, в то время как код, который это заменяет, не сделал, как отмечено bernie в его ответ .

, Если это верно, тогда можно ли обработать его при помощи unique_ptr вместо vector или, если случай не является исключительным в строке кода, на самом деле запишите класс buffer_owner, который будет владеть той памятью, и предоставлять Вам легкий и безопасный доступ к нему, включая премии как изменение размеров его (использование realloc?), или независимо от того, что Вам нужно.

66
ответ дан Community 4 November 2019 в 14:49
поделиться

Векторы используют немного больше памяти, чем массивы, поскольку они содержат размер массива. Они также увеличивают размер жесткого диска программ и, возможно, объем памяти программ. Это незначительное увеличение, но может иметь значение, если вы работаете со встроенной системой. Хотя в большинстве мест, где эти различия имеют значение, вы бы использовали C, а не C ++.

1
ответ дан 23 November 2019 в 05:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: