- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
const char *GetExternalFilesDir ()
{
assert (started);
static std::string s="";
if (s.length()==0)
{
LOGI("Try get external files dir");
jclass c; jmethodID m; jobject o;
c = env->FindClass ("android/app/NativeActivity");
m = env->GetMethodID (c, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
o = env->CallObjectMethod (appState->activity->clazz, m, NULL);
c = env->GetObjectClass (o);
m = env->GetMethodID (c, "getAbsolutePath", "()Ljava/lang/String;");
o = env->CallObjectMethod (o, m);
jstring jo = (jstring)o;
const char *path = env->GetStringUTFChars(jo, NULL);
s=path;
env->ReleaseStringUTFChars(jo, path);
s+='/';
LOGI("Path for program's data files is %s", s.c_str());
}
return s.c_str();
}
Этот код был написан одним очень известным в очень узких кругах человеком. Будем надеяться, что он придет в обсуждение и прокомментирует его.
someone 05.11.2014 06:17 # 0
bormand 05.11.2014 06:27 # −1
В const char *.
Ну и не потокобезопасно, но на это, скорее всего, пофиг.
absolut 05.11.2014 08:27 # +1
bormand 05.11.2014 08:45 # 0
Да ничего особо страшного. Просто потом автор к нему по-любому будет конкатенировать имена файлов. А с джвумя const char * (второй - литерал с именем файла) это делать малость противно.
absolut 05.11.2014 08:25 # 0
someone 05.11.2014 08:30 # −1
bormand 05.11.2014 08:39 # +1
А со статиком UB'а нет*. Да и переменная только для чтения, поэтому бояться за буфер, возвращаемый c_str не придётся.
* если джва потока не войдут в GetExternalFilesDir() в первый раз одновременно
absolut 05.11.2014 09:02 # 0
переменную только для чтения можно познакомить с const_cast. Надо копию возвращать. Полюбэ.
bormand 05.11.2014 09:38 # +5
А чем она поможет этому коду?
s атомарно и ровно один раз проинициализируется пустой строкой, а дальше оба потока войдут в if...
absolut 05.11.2014 10:46 # −1
bormand 05.11.2014 11:00 # 0
Синхронизировать с чем? Видимо с чтением этой переменной в строках 5 и 25. Т.е. всю функцию защитить мутексом.
roman-kashitsyn 05.11.2014 11:07 # +2
Поэтому мутекс надо брать перед вызовом функции и не отпускать до окончания чтения кишков.
Проще сделать s thread-local.
bormand 05.11.2014 11:09 # +1
Ну либо понадеяться на единственность вызова инициализатора, и тупо вынести всё получение строки в отдельную функцию. Как-то так, например:
bormand 05.11.2014 13:29 # 0
roman-kashitsyn 05.11.2014 13:38 # 0
Про многопоточную среду c++98 не слышал и никаких гарантий тут дать не может.
bormand 05.11.2014 14:14 # 0
Само собой.
Но ведь почти все реализации стандарта знают о потоках. Так что можно надеяться хотя бы на implementation defined на конкретных компиляторах. Вот поэтому и спрашиваю ;)
bormand 05.11.2014 14:19 # 0
P.S. Забавы ради попробовал вызвать функцию из инициализатора статика, лежащего в ней же... terminate called after throwing an instance of '__gnu_cxx::recursive_init_error'.
bormand 05.11.2014 11:13 # 0
А учитывая то, что возвращается const char *, с которым могут сделать всё, что угодно - мутекс придется взять раз и навсегда. Ну либо отпускать вручную с вызывающей стороны, что тоже не айс...
TarasB 05.11.2014 15:36 # +1
bormand 05.11.2014 15:57 # 0
Не забывай, на сотиках стоят ARM'ы с достаточно мягкой моделью памяти. С двухъядерным ARM'ом "авось проканает" не проканывает, в отличие от интелей.
bormand 05.11.2014 16:02 # 0
bormand 05.11.2014 06:22 # 0
absolut 05.11.2014 08:25 # 0
TarasB 05.11.2014 15:36 # +1
roman-kashitsyn 05.11.2014 15:43 # 0
Если эта функция должна дёргаться из плюсового кода - нужно возвращать std::string.
Если из жабы - тип возврата должен быть jstring, нужно аллоцировать строку через env, пусть жаба её сама освобождает.
TarasB 05.11.2014 15:44 # 0
roman-kashitsyn 05.11.2014 16:12 # +1
bormand 05.11.2014 16:16 # 0
+1
Иначе получается жопа, из-за которой функцию уже никогда не переделать в возвращающую разные значения и, при этом, реентерабельную. Хотя, в случае данного кода, на это можно забить болт - каталог во время работы не меняется.
P.S. Ну либо по канонам winapi возложить ответственность за выделение памяти на пользователя функции. Но ему это не понравится.
TarasB 05.11.2014 16:16 # 0
А, в сишке же нету const char*, да? Тогда не знаю.
bormand 05.11.2014 16:17 # 0
Есть.
TarasB 05.11.2014 16:18 # +1
Если он не меняется в течение работы программы. То есть функция ведёт себя так, будто возвращает указатель на какую-то константу.
bormand 05.11.2014 16:19 # 0
Ну не особо ок, если функция может возвращать разные значения. Из-за подобной питушни со strtok жопы у разрабов стандартной либы пригорели, когда появились потоки.
> Если он не меняется в течение работы программы.
Для таких случаев - ок. Если не забыть написать в доке, что не надо вызывать free() на результате этой функции.
> ведёт себя так, будто возвращает указатель на какую-то константу
Но ведь она на самом деле возвращает указатель на какую-то константу...
roman-kashitsyn 05.11.2014 16:23 # +2
Есть. Я лично периодически использую const для индикации владения. Если функция возвращает неконстантный указатель, она как-бы-говорит-нам, что содержимое полностью принадлежит нам, мы можем туда гадить и отвечаем за его удаление.
> с которым ничего не случится
Пока не появится второй поток? Кмк, проще быстренько аллоцировать строку, чем постоянно платить за синхронизацию.
bormand 05.11.2014 16:25 # 0
И слазить в жабу по JNI, не забываем.
Хотя для файлов - насрать. Копейки по сравнению с парсингом картинок\моделек\конфигов и самим чтением с флеша, а тем более HDD.
roman-kashitsyn 05.11.2014 16:29 # +1
Можно на старте на уровне приложения закешировать. Положить всё нужное в какую-нибудь глобальную структурку Game и юзать всюду без синхронизации и лишних аллокаций.
bormand 05.11.2014 16:32 # +1
Вот кстати да. Поэтому я и не люблю ленивые синглтоны - с ними ёбли больше, чем профита.
roman-kashitsyn 05.11.2014 16:33 # +1
So true...
3.14159265 05.11.2014 16:35 # +1
+1
Их даже в жабах с многопоточными примитивами и моделью памяти из коробки, не сильно тривиально написать, а в крестах старого стандарта и вовсе можно повеситься.
TarasB 05.11.2014 16:36 # +1
Ах да, у ведра в случае исключения прога тупо виснет.
roman-kashitsyn 05.11.2014 18:28 # 0
bormand 05.11.2014 18:31 # 0
roman-kashitsyn 05.11.2014 18:36 # 0
bormand 05.11.2014 18:42 # 0
TarasB 05.11.2014 20:02 # 0
3.14159265 05.11.2014 16:28 # +1
Вот кстати да.
Но в целом вопрос спорный. "постоянно платить" - это не факт. С одной стороны синхронизация без contentionа может оказаться почти бесплатной (по цене CAS), благодаря всяким хитрым lock elision.
C другой стороны хватать мьютекс явно дороже чем алоцировать строчку.
bormand 05.11.2014 16:31 # 0
Но ведь аллоцирование строчки тоже содержит в себе атомарные операции...
3.14159265 05.11.2014 16:36 # +1
Вообще в ОС обычно есть разные типы мьютексов, легковесные работают очень быстро, при частом однопоточном доступе, но тупят когда сильная конкуренция, и наоборот.
bormand 05.11.2014 16:44 # +1
3.14159265 05.11.2014 16:48 # +1
На старте может так случиться что джва и более раз запросим у JNI.
bormand 05.11.2014 16:50 # 0
Ну так я о нем выше написал ;)
А лочку можно прикрутить уже после directory.load(). И на всех проходах кроме первого она не скажется.
3.14159265 05.11.2014 16:53 # 0
>И на всех проходах кроме первого она не скажется.
Что-то это мне напоминает... А точно! Это ведь похоже на ленивый синглтон!
Опять возвращаемся к:
Поэтому я и не люблю ленивые синглтоны - с ними ёбли больше, чем профита.
bormand 05.11.2014 16:53 # +1
3.14159265 05.11.2014 16:56 # 0
По сути это такой ленивый Future.
Только эти новые фишки всё-равно Тарасу не подойдут, он же пишет под старый стандарт.
bormand 05.11.2014 16:58 # 0
TarasB 05.11.2014 17:02 # 0
3.14159265 05.11.2014 17:05 # +1
А ты как думал? Просто профит в том что это реализовали 1 раз и правильно.
Вообще полагаю там double checked locking, типа как у борманда, только с мьютексом.
1. атомарная проверка
2. мьютекс
3. выполнение метода.
4. освободить мьютекс
То есть мьютекс предотвращает множественные вызовы на инициализации, но когда пройдет первая инициализация, то до лочки код доходить уже не будет.
Плюс сами мьютексы обычно тоже сделаны на атомиках, при отсутствии конкуренции и waitов.
Xom94ok 05.11.2014 23:22 # 0
bormand 05.11.2014 23:30 # 0
Может. Но если она мютексе, то, скорее всего, на этой архитектуре по-другому его уже никак не запилить. Или авторы компилятора - ленивые обезьяны. Имхо.
TarasB 05.11.2014 16:28 # 0
TarasB 05.11.2014 16:35 # 0
TarasB 05.11.2014 14:32 # +4
http://www.gamedev.ru/projects/forum/?id=193863&page=9#m128
Ещё он говорит что я должен использовать указатели, иначе зачем мне С++.
Алсо поздравьте с первым местом
http://www.gamedev.ru/flame/forum/?id=193145
3.14159265 05.11.2014 14:34 # +1
>Ещё он говорит что я не должен использовать указатели, иначе мне С++.
>Алсо поздравьте с первым местом
Малаца. А хуле, народ не проведешь...
Хотя я кроме Хулиона не видел игр других участников, но игрушка - зачётный олдскул.
TarasB 05.11.2014 14:42 # 0
Другие игры можно по видео прикинуть: http://www.gamedev.ru/flame/forum/?id=135442&page=9#m132
3.14159265 05.11.2014 14:52 # 0
А оно когда генерирует уровень, как проверяет что его можно пройти?
Ну что ключи и двери будут открываться по мере прохождения?
PS> Мне понравилось когда стреляешь, как мясо разлетается...
TarasB 05.11.2014 15:35 # 0
Я собираюсь статью написать, но мне пока влом.
Ждите обновления в теме проекта.
3.14159265 05.11.2014 15:57 # 0
// поиск1: в сторону пустой ячейки
// поиск2: вылезти в место, где были ранее
// злоупотреблять не стоит, а то одни двери везде будут, лол
// поиск3: поход против шерсти
// поиск4: куда попало
TarasB 05.11.2014 16:10 # +1
OCEHHuu_nemyx 16.10.2020 13:52 # 0
defecate-plusplus 05.11.2014 14:40 # +1
TarasB 05.11.2014 14:45 # +1
3.14159265 05.11.2014 15:08 # +2
http://www.gamedev.ru/files/?id=101336
И комментарии экспертов
Ты не тот язык программирования выбрал, тебе надо писать на C#.
Какая-то странная помесь C-стиля, STL и BOOST. Сквозь весь проект висит std::stringstream, в котором объявлены в том числе и std::string, но многие функции принимают const char *. Указатели почти нигде не используются, управления памятью тоже нет. Есть классы, но рядом мы видим глобальные функции, принимающие указатель на структуру.
В общем, стиля нет. Либо ты каждый кусок кода рождаешь путём экспериментов со средствами языка, либо разные части кода писали разные люди, либо разные части кода написаны в разом психическом состоянии...
TarasB 05.11.2014 15:32 # 0
3.14159265 05.11.2014 16:02 # 0
Указатели почти нигде не используются, управления памятью тоже нет.
Есть классы, но рядом мы видим глобальные функции, принимающие указатель на структуру.
Он так говорит будто указатели и ручное управление памятью - что-то хорошее.
Но стиль действительно необычный. Если любовь к struct я понять еще могу (сам часто пишу бубличные поля), но вот почему весь код в h-файлах?
TarasB 05.11.2014 16:09 # +1
Именно это он и имеет в виду. А ты думал, что школоло-кулхацкеры - это я преувеличивал?
> но вот почему весь код в h-файлах
ну меня с дельфей заебало писать заголовки методов по два раза, думать, что выносить наружу, что не выносить
и первый мой опыт на крестах обломал меня с шаблонами в cpp и с глобальными переменными, поэтому я cpp недолюблюваю
bormand 05.11.2014 16:12 # 0
Бустянка.
3.14159265 05.11.2014 16:17 # +1
Плюс Тарас же ненавидит буст, и что главное в Аде такое разделение практикуется повсеместно.
http://www.adahome.com/ammo/cpp2ada.html#2
Any Ada package on the other hand consists of two parts, the specification (header) and body (code). The specification however is a completely stand alone entity which can be compiled on its own and so must include specifications from other packages to do so. An Ada package body at compile time must refer to its package specification to ensure legal declarations, but in many Ada environments it would look up a compiled version of the specification.
Имхо, писать побольше всякого кода (желательно шаблонных рекурсивных compile-time 'оптимизаций') в h-файлы - лучший способ замедлить компиляцию юзерам этих самых h-файлов.
TarasB 05.11.2014 16:19 # +1
Abbath 06.11.2014 02:24 # 0
3.14159265 05.11.2014 15:15 # +1
Это дизеринг? А чо свищ, а не массив, например?
TarasB 05.11.2014 15:34 # +1
Abbath 06.11.2014 02:24 # +1
TarasB 05.11.2014 22:14 # +1
http://www.gamedev.ru/projects/forum/?id=193863&page=10#m143
3.14159265 05.11.2014 23:03 # 0
Эх. Завлекает...
Не ведитесь, там нет ничего о генераторе бреда, только гейдев.