Я часто сталкиваюсь с ситуацией, когда у меня есть переменная члена массива, а внешние функции должны обращаться к ее элементам. Возьмем в качестве примера следующий код:
class example_t
{
protected:
int* array;
size_t size;
public:
example_t(size_t size = 100) : size(size)
{
array = new[size];
// .. fill the array ..
}
~example_t()
{
delete[] array;
}
size_t get_size(void) const { return size; }
int const * get_array(void) const { return array; }
int get_array_element(size_t n) const { return array[n]; }
};
Какой интерфейс должен быть предпочтительным методом доступа к массиву, get_array()[n]
или get_array_element(n)
? Я пытаюсь рассмотреть здесь как стиль, так и возможность дублирования вызовов, устраненных оптимизатором, например, если array
хранит некоторые индексы в другом массиве и мы хотим вычислить
example_t subset(1000);
for (int i = 0; i < subset.get_size(); i++)
{
result[subset.get_array_element(i)] = f(input[subset.get_array_element(i)]);
}
то можно было бы надеяться, что повторные вызовы будут устранены компилятором. Может ли выбор интерфейса повлиять на возможные оптимизации?
Примечание. Я знаю, что я мог бы использовать std::vector<int> array
, это просто пример.
Это полностью зависит от того, что должен делать ваш код, и, вероятно, не влияет на оптимизацию вообще. Либо ваш класс загружает указатель и разыгрывает его, либо ваш сайт вызова. В любом случае, если вы делаете это в цикле, результат будет точно таким же. Вы должны измерить его, чтобы быть уверенным, но я был бы удивлен, увидев здесь какую-либо разницу.
Поскольку это C++, возможно, вы использовали бы оператор [] вместо get_array_element (n), но это просто разные синтаксисы и должны быть одинаковыми с точки зрения производительности.
Я думаю, что самое большое влияние будет на то, сможет ли компилятор встроить эти функции. Это зависит от их размера (сейчас они крошечные, да, да), уровень оптимизации, который вы компилируете, и где живет класс. Если это в файле заголовка или в том же файле, что и код, который его использует, тогда да.
Но если методы определены в отдельном файле C++, который скомпилирован в отдельный модуль, то компилятор не сможет в первую очередь вызвать вызовы функций. В этом случае вопрос о вызове метода для получения каждого элемента будет иметь значение.
Также, если вы сделаете методы виртуальными и получите доступ к подклассу с помощью указателя базового класса, это также приведет к поражению вложения.
Если вы хотите сделать какие-либо проверки здравомыслия по индексам, то возврат указателя на массив не может быть и речи.
Я бы зашел так далеко, чтобы сказать, что если у вас будет функция, которая возвращает указатель на массив, вы можете просто сделать массив открытым. Трудно представить себе какую-либо выгоду, которую получит метод доступа.
Если вы пытаетесь найти стандартный подход для многих таких классов, имейте в виду, что вместо указателя вместо экземпляра вместо указателя вместо указателя (например, класса с конструктором копирования) может быть быстрее указатель.
С другой стороны, стандарт уже существует в виде операторов const и non const [], и я был бы склонен имитировать те, даже если их использование напрямую не подходит.
int
.
operator []
?