Теперь проблема - т.к. мы передаем указатель, то мы должны в месте вызова функции делать массив динамическим, т.е. членом класса, чего сильно не хочется. Использовать контейнер можно, но выглядеть будет очень громоздко всего лишь для вызова одной функции (1 строка будет под его объявление, 2,...,n+1 будут заняты под push_back-и или insert-ы). К сожалению, компилятор старого стандарта не поддерживает инициализацию при объявлении того же вектора. Как лучше обойти данный момент?
красиво - это отдельные классы для Menu, MenuItem (и его производных), ItemFactory и так далее. Много текста, долго и нудно делать, зато «лучше день потерять, потом за час долететь».
ваш метод «menu.AddEnumSwitch(„Некий пункт“,param, 2);» видимо делает «menu.add(EnumSwitch(..))» - то есть смешивает реализацию разных сущностей в один класс, откуда потом вырастет гораздо большие проблемы чем «неудобно писать»
зы. А что заставляет делать собственные меню при очевидном наличии аналогов во фреймворке ?
Вы уверены, что это лучше чем const char* param[] = {«Да», «Нет»};
Да, уверен. Помести туда, например, строки длиной более килобайта и посмотри, что с ними будет. Раньше я все делал с помощью char *, но потом понял, что это небезопасно и неудобно в использовании.
Эмм почему паскаль? Что именно не нравится? Типичный гугловский код стандарт (пробел только забыл)
class Menu
{
public:
Menu(MenuAttributes attributes, int y0newString);
~Menu();
void AddNumericSwitch(std::string title, int startValue, int minValue, int maxValue, int stepValue, int countSymbols = 0);
void AddEnumSwitch(std::string title, std::string* values, int countValues);
void Draw();
void PushLeft();
void PushRight();
void PushUp();
void PushDown();
void PushEnter();
private:
void createFont();
MenuAttributes _mAttr;
int _y0newString;
int _countCursorPosition;
int _cursor;
Panel* _panel;
std::vector<Widget *> _strings;
};
Да, уверен. Помести туда, например, строки длиной более килобайта и посмотри, что с ними будет.
Строка меню более килобайта длинной? У вас явно что то не так. А что, кстати, будет то?
Раньше я все делал с помощью char *, но потом понял, что это небезопасно и неудобно в использовании.
Почему небезопасно и неудобно?
Эмм почему паскаль? Что именно не нравится? Типичный гугловский код стандарт (пробел только забыл)
В массиве у вас два элемента, а вы передаете индекс, выходящий за границу. Потому и подумал, что раньше писали на паскале, поскольку там индексация начинается с единицы.
void AddNumericSwitch(std::string title, int startValue, int minValue, int maxValue, int stepValue, int countSymbols = 0); void AddEnumSwitch(std::string title, std::string* values, int countValues);
std::string title - вы уверены, что понимаете, что делаете?
В массиве у вас два элемента, а вы передаете индекс, выходящий за границу. Потому и подумал, что раньше писали на паскале, поскольку там индексация начинается с единицы.
Передаётся, наверное, не индекс а размер.
Внутри будет что-то типа
for(int i = 0; i < size;...
Опять же, это с стл вполне согласуется (передача «итератора» на элемент следующий за последним).
Кстати, в паскале при обьявлении массива указывается с какого индекса он начинается:
var
i: Integer;
b: array [50..100] of Integer;
А для динамических массивов индексация начинается как раз с нуля.
Правда, мне кажется, что всё же не стоит полагаться.
Недавно вместо хитрой арифметики отрезков я взял и тупо сделал цикл под всем элементам массива (около 30 тысяч). И знаешь что? Никакого значимого влияния на производительность. Всё время уходит на операции с диском. Сначала это была заглушка, я хотел её потом переписать «чтобы было красиво», но сейчас не вижу причины делать из короткого и простого кода сложный и запутанный ради каких-то сотых долей процента.
Scott Meyers (in Effective C++) recommends that you use pass by const ref for all types, except for builtin types (char, int, double, etc.), for iterators and for function objects (classes deriving from std::*_function).
string itos(int i)
{
stringstream ss;
ss << i;
return ss.str();
}
int main(void)
{
string s = itoa(10);
cout << s << endl;
}
versus
void itos(int i, string &s)
{
stringstream ss;
ss << i;
s = ss.str();
}
int main(void)
{
string s;
itoa(10, s);
cout << s << endl;
}
itoa(10, s) менее очевидно, чем itoa(10), разве нет? Даже в таком примере видно, что код яснее и меньше напрягает мозг. У меня мозг ограничен и я хочу освободить там место для более важных, чем жонглирование параметрами, вещей. Поэтому для меня правильный вариант — первый.
Да никто не спорит. Как и песимизация. А пруф касаемо, утверждения, что Скотт Майерс рекомендует всё передавать по (не)константной ссылке кроме простых типов. И ему я пока больше верю.
ты бы не верил, а подумал своей головой почему так.
const string & даёт возможность не вызывать копирующий конструктор. в этом вся фишка. да вот беда, const запретит менять строку, а следовательно cow не будет. а передача string по значению будет тем же, что и передать long long например. так что разницы нет, писать только больше.