Лучшая практика для обработки данных константного класса

Скажем, у вас есть определенный класс, в котором каждый экземпляр должен иметь доступ к одному и тому же набору данных. Более эффективно объявлять данные вне класса, а не заставлять каждый экземпляр создавать свои собственные, но не нарушает ли это правило «отсутствия глобальных переменных»?

Пример кода:

Фу.ч

class Foo{
    Foo();
    void someFunction();
};

Foo.cpp

#include "Foo.h"

//surely ok since it's only global to the class's .cpp?
const int g_data[length] = {
//contains some data
};

Foo::someFunction(){
//do something involving g_data ..
}

.. вместо того, чтобы делать «g_data» переменной-членом. Или есть другой способ избежать создания глобального?


person Robomoo    schedule 12.09.2014    source источник


Ответы (5)


Используйте модификатор static, который изменяет объявление члена класса, чтобы оно было общим для всех экземпляров класса. Пример:

class A {
 int length = 10;
 static int g_data[length]; //Inside the class
}

И тогда вы можете получить к нему доступ следующим образом:

int main(void) {
 std::cout << "For example: " << A::g_data[2] << std::endl;
}

Вы можете найти больше по этому вопросу здесь

person KiaMorot    schedule 12.09.2014

Вот для чего нужен статический элемент.

Таким образом, вы будете иметь в своем объявлении:

class Foo{
    Foo();
    void someFunction();
    static int const sharedData[length];
};

И где-то в вашем файле cpp:

int const Foo::sharedData[length] = { /* Your data */ };
person Quentin    schedule 12.09.2014

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

Подробности: много ответов, рекомендующих члена класса static, и это часто хороший способ, но имейте в виду, что:

  • член класса static должен быть указан в определении класса, поэтому в вашем случае он будет в Foo.h, и любой клиентский код, который включает этот заголовок, вероятно, захочет перекомпилировать, если вы каким-либо образом отредактируете член static, даже если он частный и не имеет к ним прямого отношения (это наиболее важно для классов в низкоуровневых библиотеках с разнообразным клиентским кодом — корпоративных библиотек и тех, которые совместно используются в Интернете и используются большими клиентскими приложениями)

  • с членом класса static код в заголовке может использовать его (в этом случае перекомпиляция будет необходима и уместна, если член static изменится)

  • если вы помещаете данные в файл .cpp, лучше всего в анонимном пространстве имен, чтобы у него не было внешней связи (никакие другие объекты не видят его или не могут ссылаться на него), хотя у вас нет возможности инкапсулировать его, чтобы защитить его от доступ другими функциями позже в единице трансляции .cpp (тогда как непубличный член класса static имеет такую ​​защиту)

person Tony Delroy    schedule 12.09.2014
comment
Согласованный. Анонимные пространства имен — отличный способ содержать файлы .h в чистоте, что хорошо не только во время компиляции, но и для разработчиков, которые читают ваш файл .h как документацию вашего API. - person Gavin Lock; 27.11.2014

На самом деле вам нужны данные, принадлежащие типу, а не экземпляру этого типа. К счастью, в C++ есть инструмент, делающий именно это — члены класса static.

person grzkv    schedule 12.09.2014

Если вы хотите избежать глобального и иметь более объектно-ориентированное решение, взгляните на шаблон легковеса. библиотека Boost Flyweight имеет некоторую вспомогательную инфраструктуру и дает достойное объяснение концепции.

Поскольку вы говорите об эффективности, использование такого подхода может быть или не быть хорошей идеей, в зависимости от вашей реальной цели. Легковесы больше связаны с экономией памяти и вводят дополнительный уровень косвенности, который может повлиять на производительность во время выполнения. Сохраненное извне состояние может повлиять на оптимизацию компилятора, особенно на встраивание и снижение локальности данных, что препятствует эффективному кэшированию. С другой стороны, некоторые операции, такие как присваивание или копирование, могут быть значительно быстрее, потому что есть только указатель на общее состояние, которое нужно скопировать (плюс неразделяемое состояние, но его все равно нужно скопировать). Как всегда, когда дело доходит до эффективности/производительности, убедитесь, что вы измеряете свой код, чтобы сравнить то, что соответствует вашим требованиям.

person Jens    schedule 12.09.2014