Ни насколько не допустимо. К тому же, mfn.size() в данном случае 0.
D>По уму в строках память должна выделяться непрерывно, но вот может ли это измениться?
Это тебе кажется, что "по уму", а мне кажется, что есть стандарт языка, и в нём непрерывность гарантируется только для std::vector (и для std::string::c_str(), но этот метод возвращает константный указатель, который теоретически не обязан совпадать с собственно внутренним буфером строки).
D>По уму в строках память должна выделяться непрерывно, но вот может ли это измениться?
Дело в том, что непрерывность массива символов гарантирована только для указателей, возвращаемых при вызове data() и c_str(), но при этом сами массивы доступны только для чтения. Это вроде как было сделано в древние времена чтобы позволить использовать в реализациях ::std::string всякие хитрые приемы (типа copy on write) для снижения количества копирования. Запись минуя методы string посредством хаков вроде const_cast<char *>(text.data()) или &text[0] — это прямой путь в область неопределенного поведения и удивительных багов. Так что не делайте так. Выделяйте буффер (или просто массив на стеке) и копируйте через него. И используйте GetModuleFileNameW.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
_B_>Ни насколько не допустимо. К тому же, mfn.size() в данном случае 0.
не 0, а MAX_PATH (см. к-тор).
D>>По уму в строках память должна выделяться непрерывно, но вот может ли это измениться?
_B_>Это тебе кажется, что "по уму", а мне кажется, что есть стандарт языка, и в нём непрерывность гарантируется только для std::vector (и для std::string::c_str(), но этот метод возвращает константный указатель, который теоретически не обязан совпадать с собственно внутренним буфером строки).
В '03 не не обязана выделяться непрерывно, а в '11 должна.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, VTT,
VTT>Дело в том, что непрерывность массива символов гарантирована только для указателей, возвращаемых при вызове data() и c_str(), но при этом сами массивы доступны только для чтения.
Начиная с C++11 непрерывность массива символов гарантируется (21.4.1/5).
VTT>И используйте GetModuleFileNameW.
Здравствуйте, Vlad_SP, Вы писали:
V_S>Начиная с C++11 непрерывность массива символов гарантируется (21.4.1/5).
Начиная с C++11 c его move семантикой и умными указателями фокусы с copy on write и совместным владением буфферами по идее больше не нужны, так что они могли бы сделать и не const data() и давать писать в буфер строки напрямую.
V_S>С какой это стати??
т.е. как с какой? не каждый путь в ANSI строчке может быть представлен
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, Vamp, Вы писали:
V>В результате имеем лишнее копирование. В С++11 я бы копировал напрямую в string.
Согласен. Но тут еще одна подоплека: разумеется потом выполняем resize() по фактическому размеру строки, а потом желательно бы и shrink_to_fit(), чтобы не таскать с собой излишний буфер. И вот как будет себя вести shrink_to_fit() прямо не известно. Да и как-то кажется мне это дурным тоном, хотя...
Здравствуйте, dosik, Вы писали:
D>Согласен. Но тут еще одна подоплека: разумеется потом выполняем resize() по фактическому размеру строки, а потом желательно бы и shrink_to_fit(), чтобы не таскать с собой излишний буфер. И вот как будет себя вести shrink_to_fit() прямо не известно. Да и как-то кажется мне это дурным тоном, хотя...
Можно сначала узнать требуемый размер строки от GetModuleFileName и выделить память сразу под него.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, VTT, Вы писали:
VTT>Можно сначала узнать требуемый размер строки от GetModuleFileName и выделить память сразу под него.
Да вот в том то и дело, что не умеет он говорить сколько нужно... Он возвращает только столько, сколько влезло в буфер, а если буфера не хватило, то в GetLastError помещает ERROR_INSUFFICIENT_BUFFER.
Здравствуйте, Vlad_SP, Вы писали:
V_S>Здравствуйте, VTT, Вы писали:
VTT>>т.е. как с какой? не каждый путь в ANSI строчке может быть представлен
V_S>Да-да-да. И будем уникодные символы запихивать в std::string?
std::string — это std::basic_string< char >, но существует и std::basic_string< wchar_t >.
D> buff = std::unique_ptr<char[]>(new char[size]); //Происходит ли удаление старого буфера тут?
Да.
D> string path(std::move(&buff[0])); //Действительно ли это будет оптимальней, нежели string path(&buff[0])
Оптимальней не будет, лучше выбрать вариант без std::move.
У фундаментальных типов (у указателя в данном случае) вообще нет перемещающих конструкторов — всё делается через копирование. Ну и смысла в существовании перегрузки конструктора string, принимающего r-value ссылку на указатель, тоже нет никакого по этим причинам. Так что стоит предпочесть более короткий и понятный код.
Прогнал дебагером интереса ради, действительно в первом случае после конструктора вызывается деструктор, который выполняет delete[].
Думаю что вариант с "умным" указателем даже предпочтительней чем вектор для выделения таких "одноразовых" буферов для API.
Что касается второго случая, то действительно все равно происходит копирование, что-то я тупанул. Перемещать он умеет только строки в строки, все остальное будет копировать.
D>> string path(std::move(&buff[0])); //Действительно ли это будет оптимальней, нежели string path(&buff[0])
W>
W>Оптимальней не будет, лучше выбрать вариант без std::move. W>У фундаментальных типов (у указателя в данном случае) вообще нет перемещающих конструкторов — всё делается через копирование. Ну и смысла в существовании перегрузки конструктора string, принимающего r-value ссылку на указатель, тоже нет никакого по этим причинам. Так что стоит предпочесть более короткий и понятный код.
И для закрепления: скажем есть функция, которая возвращает например string. Ну вот так:
string SomeFunction()
{
string ResultString{};
....
// тут мы эту сроку заполняем
....
return ResultString; //или все же надо return std::move(ResultString)?
}
//последующий вызов например
string a{SomeFunction()};
string b = SomeFunction() + "qwerty";
//и т.п.
Я так понимаю, что результаты работы функции априори возвращаются как r-value и при наличии перемещающего конструктора будет перемещен, а явно указывать это нет необходимости?
Здравствуйте, dosik, Вы писали:
D>В продолжении разговора, вот вторая реанкорнация с вкусностями С++11. D>Посмотрите, нет ли тут утечки памяти: D>
D> size_t size = MAX_PATH;
D> std::unique_ptr<char[]> buff(new char[size]);
D> DWORD mfn_size = GetModuleFileName(NULL, &buff[0], size);
D> while (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
D> {
D> size *= 2;
D> buff = std::unique_ptr<char[]>(new char[size]); //Происходит ли удаление старого буфера тут?
D> mfn_size = GetModuleFileName(NULL, &buff[0], size);
D> }
D> string path(std::move(&buff[0])); //Действительно ли это будет оптимальней, нежели string path(&buff[0])
D>
Во-первых, можно использовать юникодную версию функции и сразу выделить буфер в 32К. Во-вторых, unique_ptr тут, вероятно, не нужен, т.к. все это можно сделать так же коротко и с обычным вектором (vector::resize). В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см. "во-первых" — короче говоря, вся эта возня с удвоением недостаточной ёмкости буфера вряд ли оправдана.
Здравствуйте, Warturtle, Вы писали: W>В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см.
А можно отсюда поподробнее, плз? Почему ANSI-версия не может вернуть путь длиннее чем MAX_PATH? Вроде ж там можно задать размер буфера равный СКОЛЬКО_ХОЧУ? Почему тогда ANSI-версия в принципе (я так понимаю) не может вернуть путь длиньше MAX_PATH?
Здравствуйте, Carc, Вы писали:
C>А можно отсюда поподробнее, плз? Почему ANSI-версия не может вернуть путь длиннее чем MAX_PATH? Вроде ж там можно задать размер буфера равный СКОЛЬКО_ХОЧУ? Почему тогда ANSI-версия в принципе (я так понимаю) не может вернуть путь длиньше MAX_PATH?
Эксперимента ради. Win 10. Вот что самое длинное у меня получилось создать:
D:\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\123456789012345678901234567890123456789012\1234567.txt
Дальше система ругается, мол слишком длинно — не пойдет.
Итого: 3 + 100 + 1 + 100 + 1 + 42 + 1 + 7 + 4 = 259, а MAX_PATH = 260 (на нолик в конце заложились)
Хотелось бы конечно документально об этом прочитать.
Здравствуйте, dosik, Вы писали:
D>Здравствуйте, Carc, Вы писали:
D>Эксперимента ради. Win 10. Вот что самое длинное у меня получилось создать: D>D:\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\123456789012345678901234567890123456789012\1234567.txt D>Дальше система ругается, мол слишком длинно — не пойдет. D>Итого: 3 + 100 + 1 + 100 + 1 + 42 + 1 + 7 + 4 = 259, а MAX_PATH = 260 (на нолик в конце заложились) D>Хотелось бы конечно документально об этом прочитать.
И я про тоже. В доке про это ограничение вроде ни слова!?!
Здравствуйте, Carc, Вы писали:
C>Здравствуйте, Warturtle, Вы писали: W>>В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см.
C>А можно отсюда поподробнее, плз? Почему ANSI-версия не может вернуть путь длиннее чем MAX_PATH? Вроде ж там можно задать размер буфера равный СКОЛЬКО_ХОЧУ? Почему тогда ANSI-версия в принципе (я так понимаю) не может вернуть путь длиньше MAX_PATH?
Может быть я ошибаюсь, но обычно ансишные версии функций, работающие с путями ограничены длиной MAX_PATH. Для интереса попытался запустить (на Win7) exe-файл с полным именем >> MAX_PATH (на самом деле там возможно 'БукваДиска:\<MAX_PATH>') и ничего не вышло: эксплорер ругается на настройки безопасности, а CreateProcessW возвращает "The system cannot find the path specified." (GetLastError() == 3). Так что в практическом плане все еще проще.
P.S. Про ограничения в длине путей для ансишных версий и как их обходить (в юникодных версиях функций) написано в статье Naming a File.
Здравствуйте, Warturtle, Вы писали:
W>Здравствуйте, Carc, Вы писали:
C>>Здравствуйте, Warturtle, Вы писали: W>>>В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см.
C>>А можно отсюда поподробнее, плз? Почему ANSI-версия не может вернуть путь длиннее чем MAX_PATH? Вроде ж там можно задать размер буфера равный СКОЛЬКО_ХОЧУ? Почему тогда ANSI-версия в принципе (я так понимаю) не может вернуть путь длиньше MAX_PATH? W>Может быть я ошибаюсь, но обычно ансишные версии функций, работающие с путями ограничены длиной MAX_PATH. Для интереса попытался запустить (на Win7) exe-файл с полным именем >> MAX_PATH (на самом деле там возможно 'БукваДиска:\<MAX_PATH>') и ничего не вышло: эксплорер ругается на настройки безопасности, а CreateProcessW возвращает "The system cannot find the path specified." (GetLastError() == 3)...
По короткому имени (8.3) такой исполняемый файл запустить можно, если суммарная длина пути, опять же, не превышает 260, но тогда и GetModuleFileName, вызванная из него, вернет короткий вариант пути.
Здравствуйте, Warturtle, Вы писали:
W>Здравствуйте, Carc, Вы писали:
C>>Здравствуйте, Warturtle, Вы писали: W>>>В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см.
C>> CreateProcessW возвращает "The system cannot find the path specified." (GetLastError() == 3). Так что в практическом плане все еще проще.
Должно работать с длинными путями "\\?.." и только в 64-битном приложении под 64-битной виндой
D>По уму в строках память должна выделяться непрерывно, но вот может ли это измениться?
вам стоит понять, что строки стл как впрочем и многие другие классы были созданы академиками и для реального программирования пригодны чуть менее, чем никак.
Это не более, чем абстрактные строки в вакууме, с которыми ничего нельзя делать, только сидеть и радоваться, что они есть.
Z>вам стоит понять, что строки стл как впрочем и многие другие классы были созданы академиками и для реального программирования пригодны чуть менее, чуть никак. Z>Это не более, чем абстрактные строки в вакууме, с которыми ничего нельзя делать, только сидеть и радоваться, что они есть.
А попробуйте создать свой собственный класс строк. А вот потом поиграться с ним в плане переносимости кода Вот тогда и вспомните про академизм
Здравствуйте, Zenden, Вы писали:
Z>Здравствуйте, Warturtle, Вы писали:
W>>Здравствуйте, Carc, Вы писали:
C>>>Здравствуйте, Warturtle, Вы писали: W>>>>В-третьих, функция GetModuleFileNameA не может вернуть путь длиннее MAX_PATH, поэтому нужно явно использовать GetModuleFileNameW, ну а с ней см.
C>>> CreateProcessW возвращает "The system cannot find the path specified." (GetLastError() == 3). Так что в практическом плане все еще проще.
Z>Должно работать с длинными путями "\\?.." и только в 64-битном приложении под 64-битной виндой
Ну если только 64-битное. Я пробовал и с "\\?\", и с коротким (просто именем exe-файла из папки с ним): там вообще забавно было — CreateProcessW возвращал ошибку, а GetLastError() == ERROR_SUCCESS.