В чем разница между "жестким кодированием" и передачей аргументов в отношении памяти?
Так что название это мой вопрос. В памяти аргументы могут быть расположены в стеке или куче в зависимости от того, как они инициализируются, но как обращаться с жестко закодированной информацией?
В качестве примера я буду использовать конструктор для ifstream
Какая разница между этим:
void function(){
ifstream infile("home/some/file/path");
}
против
void function(char* filePath){
ifstream infile(filePath); //filePath points to a character array which contains home/some/file/path
}
Могут ли какие-либо последствия для памяти возникнуть из-за использования одного над другим? (Многопоточность может привести к повреждению кучи, если char* не свободен и правильно? И т. Д.).
Я просто пытаюсь понять разницу и возможные последствия, чтобы я мог применить ответ к более крупной проблеме. Приветствуется всякое понимание, и вы можете поправить меня, если я сделал какие-либо неверные заявления / предположения!
3 ответа
Литералы (как показано в первом примере) помещаются в часть статической инициализации исполняемого файла (поэтому, если вы работаете в системе *Nix), вы можете использовать команду strings
и получить список всех литералов в приложении.
Ваш второй пример должен быть изменен на
void function(const char* filePath) { ... }
Если вы не собираетесь изменять указатель в функции. Память для этой функции может поступать откуда угодно (строковый литерал, передаваемый в функцию, постоянная строка, объявленная где-то еще в приложении, строка, хранящаяся в памяти и вводимая из командной строки или консоли и т. Д.)
Основная проблема, с которой вы столкнетесь при использовании многопоточности, заключается в том, что потоки 2+ пытаются одновременно загрузить один и тот же файл. Это не может быть проблемой, если они все читают его, но если у вас есть поток, который хочет записать в него и получает монопольную блокировку файла, другие потоки будут тупиковыми. Однако это не имеет прямого отношения к вашему вопросу о строках.
Другие довольно хорошо показали, что буквальная строка хранится в некоторой доступной только для чтения памяти в исполняемом файле, и указатель на char просто указывает прямо на эту память.
Является ли ваш второй вариант "хорошим", "плохим" или "ничего из вышеперечисленного", в значительной степени зависит от того, каково происхождение filePath
является.
Понятно, если какой-то код делает char *filename = new char [x]; strcpy(filename, "...");
тогда должен быть соответствующий delete [] filename;
- и x
должен быть достаточно длинным для строки "..."
подходить.
Безопаснее использовать std::string
в этом случае, как и любое распределение, выполняется классом, а удаление - в деструкторе.
Если мы добавляем потоки в уравнение, нам также придется беспокоиться о том, где определены строки. В классе, который имеет только один экземпляр, как глобальная переменная или в стеке. Только "стек" является безопасным, и с ограничениями: если вы передаете указатель на char *
от main
[или какая-либо другая функция перед созданием потока] в потоке, вы можете получить всевозможные "забавы", когда память выделяется несколько раз в одну строку, данные перезаписываются другими потоками и что у вас есть. Конечно, если потоки не меняют данные, также нет проблем с глобальной переменной или стеком вне потока.
Это то, что я имел в виду, "это зависит от того, как создается строка". Детали, безусловно, имеют значение здесь.
"Жестко закодированные" или буквальные значения обычно являются частью инструкций программы. Например, если я делаю что-то вроде
int i = 0;
значение 0 загружается с помощью команд сборки на архитектурном уровне. Так что я понимаю, что они обрабатываются компилятором и программой и, вероятно, либо вообще не будут использовать память, либо будут находиться в стеке.
Для таких значений, как char*, во-первых, я бы порекомендовал использовать строки, так как они соответственно распределяют память, но большие строки часто хранятся в куче, в то время как небольшие строки (менее 7 символов или около того) можно оптимизировать так, чтобы они обрабатывается в стеке (если не указано "new").