Ivan355
Новенький
Offline
|
|
« : 06-04-2017 11:36 » |
|
Всем доброго времени суток! Нужна ваша подсказка! Возникла проблема с рекурсивным поиском файлов. Накидал я функцию, но при работе выводит бесконечный список одинаковых файлоы и деректорий. Пытался переделать, были тоже ошибки выводился не весь список, или вообще ничего. Помогите доделать функцию, чтобы она работала правильно! Делал на основе примеров из гугла. В строках way_1, 2 и 3 храню путь. Вход функции search_file( "C:\\", "*.*"). Спасибо за помощь!!! int search_file(string dir, string mask) { const char white_list_1[] = "Programm Files"; const char white_list_2[] = "Programm Files (x86)"; const char white_list_3[] = "Windows"; string way_1 = dir; string way_2 = dir; string way_3 = way_2; way_1 = way_1 + mask; HANDLE hand; WIN32_FIND_DATA data_file; hand = FindFirstFile((way_1).c_str(), &data_file); if (hand != INVALID_HANDLE_VALUE) { do { if (lstrcmpA(data_file.cFileName, ".") == 0 || lstrcmpA(data_file.cFileName, "..") == 0) { continue; } if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || lstrcmpA(data_file.cFileName, white_list_2) == 0 || lstrcmp(data_file.cFileName, white_list_3) == 0) { continue; } if (data_file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { continue; } if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { way_1 = dir + data_file.cFileName + '\\'; cout << "dir -" << way_1 << endl; search_file(way_1, mask); } else { way_3 = way_3 + data_file.cFileName; cout << "file-" << way_3 << endl; }
} while (FindNextFile(hand, &data_file)); FindClose(hand); } return (1); }
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #1 : 06-04-2017 13:03 » |
|
Можно увидеть весь код программы? И, опечатка? int search_file(string dir, string mask) { ... if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || \ lstrcmpA(data_file.cFileName, white_list_2) == 0 || \ lstrcmp(data_file.cFileName, white_list_3) == 0) ... } Везде lstrcmpA, кроме lstrcmp.
|
|
|
Записан
|
|
|
|
Ivan355
Новенький
Offline
|
|
« Ответ #2 : 06-04-2017 14:05 » |
|
Добрый день. Эта функция пока всё что у меня есть. В планах было после получения списка, что то делать с файлом, например нужный считывать или копировать. Я написал эту функцию и решил протестировать, в результате она не работает. Так и сижу на ней, пытаюсь понять что не так. Вродь нарыл, что нужно к пути добавить найденную папку и вызвать функцию снова, вродь так и делаю, а толку ноль. Да там ошибка, я забыл А в конце дописать...
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #3 : 06-04-2017 14:36 » |
|
Общие соображения таковы: Когда Вы вызываете FindFirstFile, то он возвращает некий указатель, который в дальнейшем используется FindNextFile. Хранится hand, как переменная внутри функции, поэтому, когда происходит вложенный вызов это значение возможно изменится, и после возврата будет ссылаться на ветвь поиска, которая завершилась. Стало быть, хранить эту переменную нужно принудительно в стеке текущего вызова функции. Как это сделать лучше стоит поинтересоваться у более опытных участников. Чтобы разобраться попробуйте создать тестовое дерево директорий для поиска без файлов: С:\FIND_TEST\ С:\FIND_TEST\1 С:\FIND_TEST\2 С:\FIND_TEST\2\21 С:\FIND_TEST\2\22 С:\FIND_TEST\3 Далее, привести на форуме весь код, и вывод консоли. Для теста лучше упростить: int search_file(string dir, string mask) { string way = dir + mask;
WIN32_FIND_DATA data_file;
HANDLE hand = FindFirstFile((way).c_str(), &data_file);
if (hand != INVALID_HANDLE_VALUE) {
do {
if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
way = dir + data_file.cFileName + '\\'; cout << way << endl; search_file(way, mask); }
} while (FindNextFile(hand, &data_file));
FindClose(hand); } return (1); } Добавлено через 6 часов, 52 минуты и 40 секунд:Немного попрактиковался, конечно, далеко от идеала, и на С: #include <stdio.h> #include <malloc.h> #include <windows.h>
char* stradd(char* first, char* second) {
unsigned int size = strlen(first) + strlen(second) + 1; char* total = malloc(size);
if (!total) return 0;
char* dst = total; char* src = first;
for (unsigned int i = 0; i < strlen(first); i++) {*dst++ = *src++;}
src = second;
for (unsigned int i = 0; i < strlen(second); i++) {*dst++ = *src++;}
*dst = (char)0;
return total; }
void my_search_tree(char* dir, char* mask, int depth) {
WIN32_FIND_DATA d;
char* path = stradd(dir, mask); if (!path) return;
/* printf("PATH: %s\n", path); */
HANDLE h = FindFirstFile(path, &d);
if (!h) return;
do {
if (d.cFileName[0] != '.') {
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
for (unsigned int j = 0; j < depth; j++) printf(" ");
printf("FOUND: %s\n", d.cFileName);
char* service = "\\"; char* new_path_1 = stradd(dir, d.cFileName);
if (!new_path_1) return;
char* new_path_2 = stradd(new_path_1, service);
if (!new_path_2) return;
my_search_tree(new_path_2, mask, depth + 1);
free(new_path_2); free(new_path_1); } }
} while(FindNextFile(h, &d));
free(path); }
int main(int argc, char* argv) {
my_search_tree("C:\\TDM64\\", "*.*", 0);
return 0; } Результат: FOUND: bin FOUND: gdb32 FOUND: bin FOUND: DLLs FOUND: lib FOUND: bsddb FOUND: compiler FOUND: ctypes FOUND: macholib FOUND: curses FOUND: distutils FOUND: command FOUND: email FOUND: mime FOUND: encodings FOUND: ensurepip FOUND: _bundled FOUND: hotshot FOUND: idlelib FOUND: idle_test FOUND: importlib FOUND: json FOUND: lib-tk FOUND: test FOUND: test_tkinter FOUND: test_ttk FOUND: lib2to3 FOUND: fixes FOUND: pgen2 FOUND: tests FOUND: data FOUND: fixers FOUND: myfixes FOUND: logging FOUND: msilib FOUND: multiprocessing FOUND: dummy FOUND: pydoc_data FOUND: site-packages FOUND: sqlite3 FOUND: test FOUND: audiodata FOUND: capath FOUND: cjkencodings FOUND: crashers FOUND: decimaltestdata FOUND: imghdrdata FOUND: leakers FOUND: subprocessdata FOUND: tracedmodules FOUND: xmltestdata FOUND: unittest FOUND: wsgiref FOUND: xml FOUND: dom FOUND: etree FOUND: parsers FOUND: sax FOUND: share FOUND: gdb FOUND: python FOUND: gdb FOUND: command FOUND: function FOUND: printer FOUND: syscalls FOUND: system-gdbinit FOUND: gdb64 FOUND: bin FOUND: DLLs FOUND: lib FOUND: bsddb FOUND: compiler FOUND: ctypes FOUND: macholib FOUND: curses FOUND: distutils FOUND: command FOUND: email FOUND: mime FOUND: encodings FOUND: ensurepip FOUND: _bundled FOUND: hotshot FOUND: idlelib FOUND: idle_test FOUND: importlib FOUND: json FOUND: lib-tk FOUND: test FOUND: test_tkinter FOUND: test_ttk FOUND: lib2to3 FOUND: fixes FOUND: pgen2 FOUND: tests FOUND: data FOUND: fixers FOUND: myfixes FOUND: logging FOUND: msilib FOUND: multiprocessing FOUND: dummy FOUND: pydoc_data FOUND: site-packages FOUND: sqlite3 FOUND: test FOUND: audiodata FOUND: capath FOUND: cjkencodings FOUND: crashers FOUND: decimaltestdata FOUND: imghdrdata FOUND: leakers FOUND: subprocessdata FOUND: tracedmodules FOUND: xmltestdata FOUND: unittest FOUND: wsgiref FOUND: xml FOUND: dom FOUND: etree FOUND: parsers FOUND: sax FOUND: share FOUND: gdb FOUND: python FOUND: gdb FOUND: command FOUND: function FOUND: printer FOUND: syscalls FOUND: system-gdbinit FOUND: include FOUND: lib FOUND: gcc FOUND: x86_64-w64-mingw32 FOUND: 5.1.0 FOUND: 32 FOUND: adainclude FOUND: adalib FOUND: finclude FOUND: adainclude FOUND: adalib FOUND: finclude FOUND: include FOUND: c++ FOUND: backward FOUND: bits FOUND: debug FOUND: decimal FOUND: experimental FOUND: ext FOUND: pb_ds FOUND: detail FOUND: binary_heap_ FOUND: binomial_heap_ FOUND: binomial_heap_base_ FOUND: bin_search_tree_ FOUND: branch_policy FOUND: cc_hash_table_map_ FOUND: eq_fn FOUND: gp_hash_table_map_ FOUND: hash_fn FOUND: left_child_next_sibling_heap_ FOUND: list_update_map_ FOUND: list_update_policy FOUND: ov_tree_map_ FOUND: pairing_heap_ FOUND: pat_trie_ FOUND: rb_tree_map_ FOUND: rc_binomial_heap_ FOUND: resize_policy FOUND: splay_tree_ FOUND: thin_heap_ FOUND: tree_policy FOUND: trie_policy FOUND: unordered_iterator FOUND: parallel FOUND: profile FOUND: impl FOUND: tr1 FOUND: tr2 FOUND: x86_64-w64-mingw32 FOUND: 32 FOUND: bits FOUND: ext FOUND: bits FOUND: ext FOUND: objc FOUND: ssp FOUND: include-fixed FOUND: install-tools FOUND: include FOUND: plugin FOUND: libexec FOUND: gcc FOUND: x86_64-w64-mingw32 FOUND: 5.1.0 FOUND: install-tools FOUND: share FOUND: doc FOUND: make FOUND: 3.82.90 FOUND: MinGW FOUND: gcc-5.1.0 FOUND: python FOUND: libstdcxx FOUND: v6 FOUND: info FOUND: man FOUND: man1 FOUND: man5 FOUND: man7 FOUND: x86_64-w64-mingw32 FOUND: bin FOUND: include FOUND: ddk FOUND: gdiplus FOUND: GL FOUND: psdk_inc FOUND: sdks FOUND: sec_api FOUND: sys FOUND: sys FOUND: lib FOUND: ldscripts FOUND: lib32 FOUND: __installer FOUND: downloaded
|
|
« Последнее редактирование: 06-04-2017 21:29 от Aether »
|
Записан
|
|
|
|
Aether
|
|
« Ответ #4 : 06-04-2017 21:34 » |
|
Кстати, что-то у меня запало, что перед переменной нужно писать stack при рекурсии, а по умолчанию компилятор и так, оказывается, в стеке создаёт экземпляры? Глянул в документацию, а TCC имеет только слова: register и static.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 07-04-2017 04:58 » |
|
Aether, я не склонен к оптимизации копеечных расходов, но вот это, мне кажется, может довольно заметно сказаться на скорости for (unsigned int i = 0; i < strlen(src); i++) {*dst++ = *src++;}
ведь будет для каждого байта вызываться strlen, а потом этот байт копироваться вот так, думаю, правильнее int len=strlen(src)+1;//+1 место под zt if(len && len<= (тут размер, выделенный под dst) ) { memmove(dst,src,len); }
никакого stack тоже не помню и не встречал. Тут компилятор лучше разберётся. А вообще, любую рекурсию можно развернуть в цикл - будет менее читаемо, но точно удобнее в отладке и по ресурсам Добавлено через 53 секунды:а ещё лучше - использовать c++
|
|
« Последнее редактирование: 07-04-2017 04:58 от Алексей1153 »
|
Записан
|
|
|
|
Dale
|
|
« Ответ #6 : 07-04-2017 08:32 » |
|
Немного попрактиковался, конечно, далеко от идеала, и на С: ... for (unsigned int i = 0; i < strlen(first); i++) {*dst++ = *src++;} ... Мне больше нравится минимализм в стиле Кернигана и Ритчи, если уж не хотите пользоваться стандартными библиотечными функциями копирования цепочек литер: ... while (*dst++ = *src++); ... никакого stack тоже не помню и не встречал. Этот копролит на самом деле называется " спецификатор класса памяти auto" и явно используется чуть реже чем никогда, поскольку все локальные переменные функции и так к нему относятся по умолчанию.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
Aether
|
|
« Ответ #7 : 07-04-2017 09:26 » |
|
а ещё лучше - использовать c++ В С++ у меня очевидность теряется, вот, например: way = dir + data_file.cFileName + '\\'; cout << way << endl; "+" - это стало быть оператор+ класса string и = тоже. При приравнивании старый way должен освободится, а с "+" должно происходить последовательное суммирование, в результате будут промежуточные выделения памяти - кто освободит их? Мне больше нравится минимализм в стиле Кернигана и Ритчи, если уж не хотите пользоваться стандартными библиотечными функциями копирования цепочек литер:
... все локальные переменные функции и так к нему относятся по умолчанию.
Минимализм - это очень хорошо. То есть, ситуация обратная, получается: если не нужно хранить в стеке, то пишем static?
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #8 : 07-04-2017 09:35 » |
|
если не нужно хранить в стеке, то пишем static? static пишем в первую очередь для того, чтобы значения переменной сохранялись между вызовами. Переменные с классом register тоже могут не попасть в стек, но у них своя специфика.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #9 : 07-04-2017 11:17 » |
|
Aether, std::string и освободит. Используй спокойно
|
|
|
Записан
|
|
|
|
Ivan355
Новенький
Offline
|
|
« Ответ #10 : 09-04-2017 08:53 » |
|
Ура, победа!!! получилось работает! переделал вот так: int search_file(char *dir, char *mask) { HANDLE hand = NULL; const char white_list_1[] = "Programm Files"; const char white_list_2[] = "Programm Files (x86)"; const char white_list_3[] = "Windows"; char way_1[MAX_PATH] = { "\0" }; char way_2[MAX_PATH] = { "\0" }; char way_3[MAX_PATH] = { "\0" }; lstrcatA(way_1, dir); lstrcatA(way_2, way_1); lstrcatA(way_1, mask); WIN32_FIND_DATA data_file; hand = FindFirstFile(way_1, &data_file); if (hand != INVALID_HANDLE_VALUE) { do { if (lstrcmpA(data_file.cFileName, ".") == 0 || lstrcmpA(data_file.cFileName, "..") == 0) { continue; } if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || lstrcmpA(data_file.cFileName, white_list_2) == 0 || lstrcmp(data_file.cFileName, white_list_3) == 0) { continue; } if (data_file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { continue; } way_1[0] = { '\0' }; lstrcatA(way_1, way_2); lstrcatA(way_1, data_file.cFileName); if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { lstrcatA(way_1, "\\"); cout << "dir -" << way_1 << endl; search_file(way_1, mask); } else { way_3[0] = { '\0' }; lstrcatA(way_3, way_2); lstrcat(way_3, data_file.cFileName); cout << "file-" << way_3 << endl; }
} while (FindNextFile(hand, &data_file)); FindClose(hand); } return (1); } помог отказ от string. Всем огромное спасибо за помощь
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #11 : 09-04-2017 10:38 » |
|
Aether, std::string и освободит. Используй спокойно
#include <iostream> #include <windows.h>
using namespace std;
void my_search_tree(string dir, string mask, unsigned int depth) {
WIN32_FIND_DATA d;
if (dir.empty() || mask.empty()) return;
string path = dir + mask;
if (path.empty()) return;
HANDLE h = FindFirstFile(path.c_str(), &d);
if (!h) return;
do {
if (d.cFileName[0] != '.') {
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
for (unsigned int j = 0; j < depth; j++) cout << " ";
cout << dir << d.cFileName << endl; string new_path = dir + d.cFileName + "\\";
my_search_tree(new_path, mask, depth + 1);
} else {
for (unsigned int j = 0; j < depth; j++) cout << " ";
cout << " " << d.cFileName << endl; } } } while(FindNextFile(h, &d)); }
int main(int argc, char* argv[]) {
string path = "C:\\TDM64\\"; cout << "START: " << path << endl;
my_search_tree(path, "*.*", 0);
return 0; } START: C:\TDM64\ C:\TDM64\bin addr2line.exe ar.exe as.exe c++.exe c++filt.exe cpp.exe dlltool.exe dllwrap.exe elfedit.exe g++.exe gcc-ar.exe gcc-nm.exe gcc-ranlib.exe gcc.exe gcov-tool.exe gcov.exe gdb.exe gdb32.exe gdb64.exe gdbserver.exe gdbserver32.exe gdbserver64.exe gfortran.exe gnat.exe gnatbind.exe gnatchop.exe gnatclean.exe gnatdll.exe gnatfind.exe gnatkr.exe gnatlink.exe gnatls.exe gnatmake.exe gnatname.exe gnatprep.exe gnatxref.exe gprof.exe ld.bfd.exe ld.exe libatomic-1.dll libatomic_64-1.dll libcharset-1.dll libgcc_s_dw2-1.dll libgcc_s_seh_64-1.dll libgcc_s_sjlj-1.dll libgfortran-3.dll libgfortran_64-3.dll libgnarl-5.dll libgnat-5.dll libgomp-1.dll libgomp-plugin-host_nonshm-1.dll libgomp-plugin-host_nonshm_64-1.dll libgomp_64-1.dll libiconv-2.dll libintl-8.dll libobjc-4.dll libobjc_64-4.dll libquadmath-0.dll libquadmath_64-0.dll libssp-0.dll libssp_64-0.dll libstdc++-6.dll libstdc++_64-6.dll libvtv-0.dll libvtv_64-0.dll libvtv_stubs-0.dll libvtv_stubs_64-0.dll libwinpthread-1.dll libwinpthread_64-1.dll mingw32-make.exe nm.exe objcopy.exe objdump.exe ranlib.exe readelf.exe size.exe strings.exe strip.exe windmc.exe windres.exe x86_64-w64-mingw32-c++.exe x86_64-w64-mingw32-g++.exe x86_64-w64-mingw32-gcc-5.1.0.exe x86_64-w64-mingw32-gcc-ar.exe x86_64-w64-mingw32-gcc-nm.exe x86_64-w64-mingw32-gcc-ranlib.exe x86_64-w64-mingw32-gcc.exe x86_64-w64-mingw32-gfortran.exe COPYING-expat.txt COPYING.ISL.txt COPYING.LIB.txt COPYING.MinGW-w64-runtime.txt COPYING.MinGW-w64.txt COPYING.RUNTIME-gcc-tdm.txt COPYING.winpthreads.txt COPYING3-gcc-tdm.txt COPYING3-gdb-tdm.txt COPYING3.LIB-gcc-tdm.txt C:\TDM64\gdb32 C:\TDM64\gdb32\bin C:\TDM64\gdb32\bin\DLLs bz2.pyd py.ico pyc.ico pyexpat.pyd select.pyd sqlite3.dll unicodedata.pyd winsound.pyd _bsddb.pyd _ctypes.pyd _ctypes_test.pyd _elementtree.pyd _hashlib.pyd _msi.pyd _multiprocessing.pyd _socket.pyd _sqlite3.pyd _ssl.pyd _testcapi.pyd gdb32.exe gdbinit gdbserver32.exe C:\TDM64\gdb32\bin\lib ...
Вопрос: по выходу из функции std::string сам вызовет деструктор, чтобы освободить память?
|
|
« Последнее редактирование: 09-04-2017 10:43 от Aether »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #12 : 09-04-2017 19:48 » |
|
Aether, а что именно ему помешает освободить?
Добавлено через 2 минуты и 35 секунд: Aether, можешь поставить эксперимент: сохрани указатель path.c_str() и в отладчике посмотри, что произойдёт с памятью в момент выхода из функции
|
|
« Последнее редактирование: 09-04-2017 19:52 от Алексей++ »
|
Записан
|
|
|
|
Aether
|
|
« Ответ #13 : 10-04-2017 09:37 » |
|
Aether, а что именно ему помешает освободить?
Я пытаюсь понять суть происходящего. Например: void test(void) {
string a = "123456"; cout << a;
} Как я понимаю: в стеке будет создан указатель на структуру класса "a", а также сама структура класса "а". Где-то в памяти будет валяться массив char, оператор= вызовет функцию, которая сопоставит данные уже имеющейся структуры класса "а" с массивом char. При таком объявлении конструктор будет вызван при входе в функцию, а деструктор при выходе из неё? Надо будет похоже мне проработать эти нюансы. string test(void) {
string a = "123456"; cout << a;
return string; } А здесь что произойдёт? Класс "a" передаст свои координаты приёмнику, а потом уничтожится?
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #14 : 10-04-2017 16:21 » |
|
Решил немного потестить: #include <iostream> #include <string>
using namespace std;
class info { public: info(string setup); ~info(); private: string base; };
info::info(string setup) { base = setup; cout << " Build - " << base << endl; }
info::~info() { cout << " Destroy - " << base << endl; }
void sub_function(unsigned int depth) { string s = to_string(depth); info sub(s); unsigned int a = depth - 1;
if (a) sub_function(a); }
int main(int argc, char* argv[]) { cout << "Start:" << endl;
cout << "Prepare first object:" << endl; info first("First");
cout << "Run sub_function:" << endl; sub_function(4);
cout << "End." << endl; return 0; } Результат: Start: Prepare first object: Build - First Run sub_function: Build - 4 Build - 3 Build - 2 Build - 1 Destroy - 1 Destroy - 2 Destroy - 3 Destroy - 4 End. Destroy - First
В общем, я мало сталкивался по серьёзному с плюсами, поэтому нюансы имеют место быть.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #15 : 10-04-2017 21:59 » |
|
void test() {
string a = "123456"; cout << a;
} "123456" - это указатель на статический массив (где этот массив расположит компилятор - нам вообще неинтересно) на стеке создаётся экземпляр std::string с именем "a" , вызывается его конструктор std::string(char*), куда передаётся ссылка на массив по выходу из функции вызывается деструктор std::~string() чистится стек можешь посмотреть дизассемблер (я в дебаге смотрел, поэтому тут такая каша и всякие проверки) ;void test() ;{ 00696D10 push ebp 00696D11 mov ebp,esp 00696D13 sub esp,2Ch 00696D16 push edi 00696D17 lea edi,[ebp-2Ch] 00696D1A mov ecx,0Bh 00696D1F mov eax,0CCCCCCCCh 00696D24 rep stos dword ptr es:[edi] 00696D26 mov eax,dword ptr [___security_cookie (0B9DD94h)] 00696D2B xor eax,ebp 00696D2D mov dword ptr [ebp-4],eax ;std::string a = "123456"; 00696D30 push offset xxx::`vftable`+180h (0AA7A5Ch) 00696D35 lea ecx,[ebp-28h] 00696D38 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (40EDE0h) ;} 00696D3D lea ecx,[ebp-28h] 00696D40 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (40EE70h) 00696D45 push edx 00696D46 mov ecx,ebp 00696D48 push eax 00696D49 lea edx,[ (696D70h)] 00696D4F call _RTC_CheckStackVars (8ED000h) 00696D54 pop eax 00696D55 pop edx 00696D56 pop edi 00696D57 mov ecx,dword ptr [ebp-4] 00696D5A xor ecx,ebp 00696D5C call __security_check_cookie (8ECFC0h) 00696D61 add esp,2Ch 00696D64 cmp ebp,esp 00696D66 call _RTC_CheckEsp (8ECFD0h) 00696D6B mov esp,ebp 00696D6D pop ebp 00696D6E ret string test(void) {
string a = "123456"; cout << a;
return string; } - это не скомпилится. Если ты имел в виду "return a;" то всё будет так же, только в стеке останется копия - возвращаемый экземпляр std::string std::string test2() {
std::string a = "123456";
return a; } ;std::string test2() ;{ 00696D90 push ebp 00696D91 mov ebp,esp 00696D93 push 0FFFFFFFFh 00696D95 push offset __ehhandler$?test2@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ (9DC490h) 00696D9A mov eax,dword ptr fs:[00000000h] 00696DA0 push eax 00696DA1 sub esp,30h 00696DA4 push edi 00696DA5 lea edi,[ebp-3Ch] 00696DA8 mov ecx,0Ch 00696DAD mov eax,0CCCCCCCCh 00696DB2 rep stos dword ptr es:[edi] 00696DB4 mov eax,dword ptr [___security_cookie (0B9DD94h)] 00696DB9 xor eax,ebp 00696DBB mov dword ptr [ebp-10h],eax 00696DBE push eax 00696DBF lea eax,[ebp-0Ch] 00696DC2 mov dword ptr fs:[00000000h],eax 00696DC8 mov dword ptr [ebp-3Ch],0
;std::string a = "123456"; 00696DCF push offset xxx::`vftable`+188h (0AA7A64h) 00696DD4 lea ecx,[ebp-34h] 00696DD7 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (40EDE0h) 00696DDC mov dword ptr [ebp-4],1
;return a; 00696DE3 lea eax,[ebp-34h] 00696DE6 push eax 00696DE7 mov ecx,dword ptr [ebp+8] 00696DEA call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (411B50h) 00696DEF mov ecx,dword ptr [ebp-3Ch] 00696DF2 or ecx,1 00696DF5 mov dword ptr [ebp-3Ch],ecx 00696DF8 mov byte ptr [ebp-4],0 00696DFC lea ecx,[ebp-34h] 00696DFF call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (40EE70h) 00696E04 mov eax,dword ptr [ebp+8] ;} 00696E07 push edx 00696E08 mov ecx,ebp 00696E0A push eax 00696E0B lea edx,[ (696E3Ch)] 00696E11 call _RTC_CheckStackVars (8ED0E0h) 00696E16 pop eax 00696E17 pop edx 00696E18 mov ecx,dword ptr [ebp-0Ch] 00696E1B mov dword ptr fs:[0],ecx 00696E22 pop ecx 00696E23 pop edi 00696E24 mov ecx,dword ptr [ebp-10h] 00696E27 xor ecx,ebp 00696E29 call __security_check_cookie (8ED0A0h) 00696E2E add esp,3Ch 00696E31 cmp ebp,esp 00696E33 call _RTC_CheckEsp (8ED0B0h) 00696E38 mov esp,ebp 00696E3A pop ebp 00696E3B ret
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #16 : 11-04-2017 04:22 » |
|
Есть довольно мошная утилитка для тестирования течи памяти в том числе. Называется valgrind. Вот лог тестирование им твоего примера. $ g++ auth.cpp -o auth -g -Wall $ valgrind ./auth ==6917== Memcheck, a memory error detector ==6917== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==6917== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==6917== Command: ./auth ==6917== Start: Prepare first object: Build - First Run sub_function: Build - 4 Build - 3 Build - 2 Build - 1 Destroy - 1 Destroy - 2 Destroy - 3 Destroy - 4 End. Destroy - First ==6917== ==6917== HEAP SUMMARY: ==6917== in use at exit: 0 bytes in 0 blocks ==6917== total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated ==6917== ==6917== All heap blocks were freed -- no leaks are possible ==6917== ==6917== For counts of detected and suppressed errors, rerun with: -v ==6917== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
|
« Последнее редактирование: 11-04-2017 04:24 от Finch »
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Aether
|
|
« Ответ #17 : 11-04-2017 17:09 » |
|
Тоже немного поэкспериментировал, теперь пытаюсь понять что тут и где: #include <iostream>
using namespace std;
class test { public: test(unsigned int setup); ~test(); void inc(); void print(); private: unsigned int value; };
test::test(unsigned int setup) { value = setup; cout << " Build" << endl; }
test::~test() { cout << " Destroy" << endl; }
void test::inc() { value++; }
void test::print() { cout << value << endl; }
test create(test in) { return in; }
int main(int argc, char* argv[]) { cout << "Start:" << endl;
cout << "Step 1: prepare first object" << endl; unsigned int a = 5; test obj_1(a); obj_1.print();
cout << "Step 2: change \"a\" value" << endl; a = 6; obj_1.print();
cout << "Step 3: change private value" << endl; obj_1.inc(); obj_1.print();
cout << "Step 4: prepare second object" << endl; test obj_2 = create(obj_1); obj_1.print(); obj_2.print();
cout << "Step 5: inc first object" << endl; obj_1.inc(); obj_1.print(); obj_2.print();
cout << "End." << endl; return 0; } .file "test_3.cpp" .intel_syntax noprefix .section .rdata,"dr" __ZStL19piecewise_construct: .space 1 .lcomm __ZStL8__ioinit,1,1 LC0: .ascii " Build\0" .text .align 2 .globl __ZN4testC2Ej .def __ZN4testC2Ej; .scl 2; .type 32; .endef __ZN4testC2Ej: push ebp mov ebp, esp sub esp, 40 mov DWORD PTR [ebp-12], ecx mov eax, DWORD PTR [ebp-12] mov edx, DWORD PTR [ebp+8] mov DWORD PTR [eax], edx mov DWORD PTR [esp+4], OFFSET FLAT:LC0 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 nop leave ret 4 .globl __ZN4testC1Ej .def __ZN4testC1Ej; .scl 2; .type 32; .endef .set __ZN4testC1Ej,__ZN4testC2Ej .section .rdata,"dr" LC1: .ascii " Destroy\0" .def ___gxx_personality_sj0; .scl 2; .type 32; .endef .def __Unwind_SjLj_Register; .scl 2; .type 32; .endef .def __Unwind_SjLj_Unregister; .scl 2; .type 32; .endef .text .align 2 .globl __ZN4testD2Ev .def __ZN4testD2Ev; .scl 2; .type 32; .endef __ZN4testD2Ev: push ebp mov ebp, esp sub esp, 88 mov DWORD PTR [ebp-12], ecx mov DWORD PTR [ebp-40], OFFSET FLAT:___gxx_personality_sj0 mov DWORD PTR [ebp-36], OFFSET FLAT:LLSDA1413 lea eax, [ebp-64] mov DWORD PTR [esp], eax call __Unwind_SjLj_Register mov DWORD PTR [esp+4], OFFSET FLAT:LC1 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout mov DWORD PTR [ebp-60], 0 call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 nop lea eax, [ebp-64] mov DWORD PTR [esp], eax call __Unwind_SjLj_Unregister leave ret .section .gcc_except_table,"w" LLSDA1413: .byte 0xff .byte 0xff .byte 0x1 .uleb128 LLSDACSE1413-LLSDACSB1413 LLSDACSB1413: LLSDACSE1413: .text .globl __ZN4testD1Ev .def __ZN4testD1Ev; .scl 2; .type 32; .endef .set __ZN4testD1Ev,__ZN4testD2Ev .align 2 .globl __ZN4test3incEv .def __ZN4test3incEv; .scl 2; .type 32; .endef __ZN4test3incEv: push ebp mov ebp, esp sub esp, 4 mov DWORD PTR [ebp-4], ecx mov eax, DWORD PTR [ebp-4] mov eax, DWORD PTR [eax] lea edx, [eax+1] mov eax, DWORD PTR [ebp-4] mov DWORD PTR [eax], edx nop leave ret .align 2 .globl __ZN4test5printEv .def __ZN4test5printEv; .scl 2; .type 32; .endef __ZN4test5printEv: push ebp mov ebp, esp sub esp, 40 mov DWORD PTR [ebp-12], ecx mov eax, DWORD PTR [ebp-12] mov eax, DWORD PTR [eax] mov DWORD PTR [esp], eax mov ecx, OFFSET FLAT:__ZSt4cout call __ZNSolsEj sub esp, 4 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 nop leave ret .globl __Z6create4test .def __Z6create4test; .scl 2; .type 32; .endef __Z6create4test: push ebp mov ebp, esp mov eax, DWORD PTR [ebp+8] mov edx, DWORD PTR [ebp+12] mov edx, DWORD PTR [edx] mov DWORD PTR [eax], edx mov eax, DWORD PTR [ebp+8] pop ebp ret .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC2: .ascii "Start:\0" LC3: .ascii "Step 1: prepare first object\0" LC4: .ascii "Step 2: change \"a\" value\0" LC5: .ascii "Step 3: change private value\0" LC6: .ascii "Step 4: prepare second object\0" LC7: .ascii "Step 5: inc first object\0" LC8: .ascii "End.\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: lea ecx, [esp+4] and esp, -16 push DWORD PTR [ecx-4] push ebp mov ebp, esp push edi push esi push ebx push ecx sub esp, 104 mov DWORD PTR [ebp-68], OFFSET FLAT:___gxx_personality_sj0 mov DWORD PTR [ebp-64], OFFSET FLAT:LLSDA1418 lea eax, [ebp-60] lea ebx, [ebp-24] mov DWORD PTR [eax], ebx mov edx, OFFSET FLAT:L11 mov DWORD PTR [eax+4], edx mov DWORD PTR [eax+8], esp lea eax, [ebp-92] mov DWORD PTR [esp], eax call __Unwind_SjLj_Register call ___main mov DWORD PTR [esp+4], OFFSET FLAT:LC2 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout mov DWORD PTR [ebp-88], -1 call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 mov DWORD PTR [esp+4], OFFSET FLAT:LC3 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 mov DWORD PTR [ebp-28], 5 lea eax, [ebp-36] mov edx, DWORD PTR [ebp-28] mov DWORD PTR [esp], edx mov ecx, eax call __ZN4testC1Ej sub esp, 4 lea eax, [ebp-36] mov DWORD PTR [ebp-88], 1 mov ecx, eax call __ZN4test5printEv mov DWORD PTR [esp+4], OFFSET FLAT:LC4 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 mov DWORD PTR [ebp-28], 6 lea eax, [ebp-36] mov ecx, eax call __ZN4test5printEv mov DWORD PTR [esp+4], OFFSET FLAT:LC5 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 lea eax, [ebp-36] mov ecx, eax call __ZN4test3incEv lea eax, [ebp-36] mov ecx, eax call __ZN4test5printEv mov DWORD PTR [esp+4], OFFSET FLAT:LC6 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 mov eax, DWORD PTR [ebp-36] mov DWORD PTR [ebp-32], eax lea eax, [ebp-40] lea edx, [ebp-32] mov DWORD PTR [esp+4], edx mov DWORD PTR [esp], eax call __Z6create4test lea eax, [ebp-32] mov ecx, eax call __ZN4testD1Ev lea eax, [ebp-36] mov DWORD PTR [ebp-88], 2 mov ecx, eax call __ZN4test5printEv lea eax, [ebp-40] mov ecx, eax call __ZN4test5printEv mov DWORD PTR [esp+4], OFFSET FLAT:LC7 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 lea eax, [ebp-36] mov ecx, eax call __ZN4test3incEv lea eax, [ebp-36] mov ecx, eax call __ZN4test5printEv lea eax, [ebp-40] mov ecx, eax call __ZN4test5printEv mov DWORD PTR [esp+4], OFFSET FLAT:LC8 mov DWORD PTR [esp], OFFSET FLAT:__ZSt4cout call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc mov DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ mov ecx, eax call __ZNSolsEPFRSoS_E sub esp, 4 mov DWORD PTR [ebp-96], 0 lea eax, [ebp-40] mov ecx, eax call __ZN4testD1Ev lea eax, [ebp-36] mov ecx, eax call __ZN4testD1Ev mov eax, DWORD PTR [ebp-96] mov DWORD PTR [ebp-96], eax jmp L14 L13: mov DWORD PTR [ebp-96], edx lea eax, [ebp-40] mov ecx, eax call __ZN4testD1Ev mov eax, DWORD PTR [ebp-96] mov DWORD PTR [ebp-96], eax jmp L10 L11: lea ebp, [ebp+24] mov edx, DWORD PTR [ebp-84] mov eax, DWORD PTR [ebp-88] test eax, eax je L12 sub eax, 1 test eax, eax je L13 sub eax, 1 ud2 L12: mov DWORD PTR [ebp-96], edx L10: lea eax, [ebp-36] mov ecx, eax call __ZN4testD1Ev mov eax, DWORD PTR [ebp-96] mov DWORD PTR [esp], eax mov DWORD PTR [ebp-88], -1 call __Unwind_SjLj_Resume L14: lea eax, [ebp-92] mov DWORD PTR [esp], eax call __Unwind_SjLj_Unregister mov eax, DWORD PTR [ebp-96] lea esp, [ebp-16] pop ecx pop ebx pop esi pop edi pop ebp lea esp, [ecx-4] ret .section .gcc_except_table,"w" LLSDA1418: .byte 0xff .byte 0xff .byte 0x1 .uleb128 LLSDACSE1418-LLSDACSB1418 LLSDACSB1418: .uleb128 0 .uleb128 0 .uleb128 0x1 .uleb128 0 LLSDACSE1418: .text .def ___tcf_0; .scl 3; .type 32; .endef ___tcf_0: push ebp mov ebp, esp sub esp, 8 mov ecx, OFFSET FLAT:__ZStL8__ioinit call __ZNSt8ios_base4InitD1Ev leave ret .def __Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef __Z41__static_initialization_and_destruction_0ii: push ebp mov ebp, esp sub esp, 24 cmp DWORD PTR [ebp+8], 1 jne L18 cmp DWORD PTR [ebp+12], 65535 jne L18 mov ecx, OFFSET FLAT:__ZStL8__ioinit call __ZNSt8ios_base4InitC1Ev mov DWORD PTR [esp], OFFSET FLAT:___tcf_0 call _atexit L18: nop leave ret .def __GLOBAL__sub_I__ZN4testC2Ej; .scl 3; .type 32; .endef __GLOBAL__sub_I__ZN4testC2Ej: push ebp mov ebp, esp sub esp, 24 mov DWORD PTR [esp+4], 65535 mov DWORD PTR [esp], 1 call __Z41__static_initialization_and_destruction_0ii leave ret .section .ctors,"w" .align 4 .long __GLOBAL__sub_I__ZN4testC2Ej .ident "GCC: (tdm64-1) 5.1.0" .def __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef .def __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_; .scl 2; .type 32; .endef .def __ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef .def __ZNSolsEj; .scl 2; .type 32; .endef .def __Unwind_SjLj_Resume; .scl 2; .type 32; .endef .def __ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef .def __ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef .def _atexit; .scl 2; .type 32; .endef Start: Step 1: prepare first object Build 5 Step 2: change "a" value 5 Step 3: change private value 6 Step 4: prepare second object Destroy 6 6 Step 5: inc first object 7 6 End. Destroy Destroy
Получается, что приравнять классы - это не то же самое, что приравнять указатели на их структуры. Самое удивительное, что при копировании не вызывается конструктор. Как же быть, если в составе класса будет указатель на какой-то выделенный блок памяти? В клоне класса будет ссылка в никуда. Мне кажется, что это не совсем логично, тогда "=" должно быть определённым пользователем методом, таким, чтобы копирование структур происходило правильно.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #18 : 11-04-2017 18:50 » |
|
Не совсем так. Вызывается конструктор копирования. Если он не определен в классе, то по умолчанию. Поэтому при динамических переменных, его нужно обязательно определять в классе.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Aether
|
|
« Ответ #19 : 11-04-2017 20:34 » |
|
А как такой конструктор организовать в рамках моего примера? Он будет надстройкой КК по умолчанию? Или же придётся полностью реализовывать копирование, в том числе, статичных элементов класса?
Впрочем, что-то стало яснее - это однозначно.)
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #20 : 11-04-2017 20:55 » |
|
Как-то так? test::test(const test& object) { value = object.value; cout << " Copy" << endl; } Start: Step 1: prepare first object Build 5 Step 2: change "a" value 5 Step 3: change private value 6 Step 4: prepare second object Copy Copy Destroy 6 6 Step 5: inc first object 7 6 End. Destroy Destroy
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #21 : 11-04-2017 21:11 » |
|
Куда ты собрался копировать статические члены класса? Они, по сути, простые статические переменные с видимостью определяемой классом. Т.е. существуют в единственном количестве.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #22 : 11-04-2017 21:28 » |
|
Как-то так?
Ага
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Aether
|
|
« Ответ #23 : 12-04-2017 11:00 » |
|
Куда ты собрался копировать статические члены класса? Они, по сути, простые статические переменные с видимостью определяемой классом. Т.е. существуют в единственном количестве.
Как куда? Из одного экземпляра в другой. Если в КК убрать: value = object.value; То в объекте приёмнике value станет произвольным числом, если же написать: value = 0; То после копирования значение сбросится на ноль, и неважно что там return возвращал. В общем, как я понял, при входе и выходе из функции, в том числе main создаётся стековый кадр на размер структуры класса, после чего, если не определён КК, происходит полное копирование данных класса источника в класс приёмник. Если же КК определён, то кадр содержит мусор, и его нужно заполнять всецело самому. А если есть динамические выделения, то управлять и ими. Сейчас думаю: чем передача по ссылке отличается от передачи по указателю?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #24 : 12-04-2017 15:02 » |
|
Или же придётся полностью реализовывать копирование, в том числе, статичных элементов класса?
Aether, RXL, немного не поняли друг друга , мне кажется не знаю, что именно Aether назвал "статичные переменные", но Рома точно подумал про статические, а тут не про них явно )) Сейчас думаю: чем передача по ссылке отличается от передачи по указателю? практически ничем
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #25 : 12-04-2017 17:09 » |
|
практически ничем
А для чего тогда так сделали?
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #26 : 12-04-2017 23:52 » |
|
Семантика ссылки и указателя разная. Для доступа к членам для ссылки используется оператор ".". С указателем используются операторы "->" и "*". Указатель может быть нулевым, а ссылка нет. Как следствие, ссылка должна быть инициализирована при создании и не может быть присвоена. Указатель может быть как инициализирован, так и присвоен.
|
|
« Последнее редактирование: 12-04-2017 23:55 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #27 : 13-04-2017 04:43 » |
|
Aether, ссылку изменить нельзя int a=0; int& ref_a1=a;//первая ссылка на а int& ref_a2=ref_a1;//вторая ссылка на a
int b=0; ref_a2=b;//изменить ссылку нельзя (здесь выполняется a=b) то есть, ссылка - это псевдоним уже существующей переменной указатель можно менять int a=0; int* ptr_a1=&a;//ptr_a1 - указатель на a *ptr_a1=1;//здесь выполняется a=1
int b=0; ptr_a1=&b;//теперь ptr_a1 - указатель на b *ptr_a1=2;//здесь выполняется b=2
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #28 : 13-04-2017 10:38 » |
|
Семантика ссылки и указателя разная.
То есть, из-за того, что класс может быть и динамическим придумано такое упрощение? Aether, ссылку изменить нельзя
Кстати, почему в шаблоне для КК нужно в качестве аргумента писать именно const?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #29 : 13-04-2017 16:44 » |
|
Aether, я не знаю такое - "динамический класс"
конструктор копирования имеет определённый прототип. Ну и это же копирование, так что источник не должен изменяться
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #30 : 13-04-2017 22:28 » |
|
Потому, что в него можно передать как const, так и не const источник. Есть аргумент будет не const, то и передать можно будет только не const. В плюсах const — часть типа. Т.е. const T и T — разные типы. А по правилам приведения типов T можно привести к const T, но не наоборот.
И не придумывай новые термины. Попробуй, к примеру, почитать самоучитель.
|
|
« Последнее редактирование: 13-04-2017 22:30 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Aether
|
|
« Ответ #31 : 14-04-2017 10:13 » |
|
Aether, я не знаю такое - "динамический класс"
И не придумывай новые термины. Попробуй, к примеру, почитать самоучитель.
"new - оператор языка С++, обеспечивающий выделение динамической памяти в куче" Стало быть: MyClass* first = new MyClass(); это будет размещением класса в динамической памяти.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #32 : 14-04-2017 15:07 » |
|
Aether, класс не бывает динамическим, это создаётся экземпляр класса
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #33 : 15-04-2017 11:23 » |
|
Aether, класс не бывает динамическим, это создаётся экземпляр класса
Как правильно обозвать разницу: MyClass first(); от MyClass* first = new MyClass();
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #34 : 15-04-2017 11:56 » |
|
Aether, 1 - создание локальной переменной на стеке 2 - создание переменной в куче и получение указателя
"переменная" и "экземпляр класса" - это, считай, одно и то же
а класс - это как бы чертёж в исходниках, по которому переменная создаётся
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #35 : 15-04-2017 13:25 » |
|
То есть, из-за того, что класс может быть и динамическим придумано такое упрощение?
То есть из-за того, что класс может быть размещён, как в стеке, так и в куче, придумано такое обобщение - ссылка? И единообразный синтаксис доступа к членам через "."? А так, на деле, я понял, что в функцию будет передан тот же указатель. Кстати, а почему в "С" появилось разделение на "." и "->"? Нет, правда интересно знать, как устроено изнутри, и главное - почему.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #36 : 15-04-2017 17:12 » |
|
Aether, "." - оператор доступа к члену класса myclass c; c.member=1; в случае указателя для доступа к члену класса требуется произвести разыменование myclass* c=new myclass; (*c).member=1; или так c->member=1; Aether, тебе выше правильно же советуют прочитать основы - там всё систематизировано будет рассказано. Посмотри, скажем, тут https://club.shelek.ru/viewfiles.php?id=16
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #37 : 15-04-2017 17:22 » |
|
Кстати, а почему в "С" появилось разделение на "." и "->"? Это "синтаксический сахар". Если b - поле структуры a, а p - указатель на a, то a.b, (*p).b и p->b - один и тот же объект, т.е. поле b структуры, на которую указывает p. Создатели C любили краткие формы записи (2 литеры вместо 4), и к тому же уберегли новичков от дурной ошибки: если "забыть" скобки в выражении (*p).b, получим совершенно другую конструкцию *p.b (или *(p.b)), т.е. объект, на который указывает указатель p.b. Дело в том, что операция выбора поля структуры " ." имеет более высокий приоритет, чем операция разыменования " *", поэтому при выборе поля структуры через указатель скобки необходимы. Нет, правда интересно знать, как устроено изнутри, и главное - почему. Читайте правильные книги. Несколько таких есть в моих обзорах, например, Expert C Programming: Deep C Secrets и Tutorial on Pointers and Arrays in C. Почитайте также блог Дэна Сакса. На несколько интересных статей я уже написал обзоры ( 1, 2, 3, 4), но их там гораздо больше. Человеку, который много лет состоял в комитете по стандартизации C и C++, определенно есть что рассказать по теме.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
|