Странное поведение деструкторов C++

Вы смешиваете списки и строки внутри другого списка, смешивая нарезку и индексацию. При нарезке создается список, индексирующий отдельный элемент.

Таким образом, рабочий код помещает только отдельных значений в список:

[plist[5], plist[4], plist[7], plist[6]]

, в то время как ваш код также использует нарезку:

[plist[1:3], plist[5], plist[4], plist[7], plist[6]]
#     ^^^^^

, так что теперь вы Первый элемент - это список из 2 элементов.

str.join() могут только соединять строки, поэтому все элементы должны быть строками, любые другие типы объектов (например, список) приводят к ошибкам.

Код в книге работает вокруг этого, соединяя результат среза отдельно:

new_phrase = ''.join(plist[1:3])

Это берет нарезанный список, передавая его str.join() напрямую (не как элемент другого списка). Затем код в книге добавляет результат второго вызова str.join() к следующему:

new_phrase = new_phrase + ''.join([plist[5], plist[4], plist[7], plist[6]])

Современный Python (3.5 или новее) имеет синтаксис для перемещения элементов из [ 1121] список в список, который вы создаете с помощью синтаксиса [...], добавляя элемент к *; это приводит к тому, что все элементы вынимаются и помещаются в текущий список. Вы также можете использовать это здесь, чтобы вынуть все нарезанные строки из среза в новый список:

''.join([*plist[1:3], plist[5], plist[4], plist[7], plist[6]])
#        ^ note the * here, meaning: take all elements from plist[1:3], not plist[1:3] itself.

Это будет зависеть от возраста книги, которую вы используете, будет ли она ввести этот синтаксис.

Всегда полезно посмотреть, что происходит с компонентными элементами выражений Python, в интерактивном интерпретаторе. Вот что происходит с вашим кодом:

>>> phrase = "Don't panic!"
>>> plist = list(phrase)
>>> plist
['D', 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!']
>>> [plist[1:3], plist[5], plist[4], plist[7], plist[6]]
[['o', 'n'], ' ', 't', 'a', 'p']

Видите этот элемент ['o', 'n'] в начале? Это не одно строковое значение, поэтому str.join() не примет его:

>>> ''.join([plist[1:3], plist[5], plist[4], plist[7], plist[6]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected str instance, list found

, но если вы проигнорировали эту часть, остаток можно объединить:

>>> ''.join([plist[5], plist[4], plist[7], plist[6]])
' tap'

Если мы используем Синтаксис *, вы получаете плоский список, и ''.join(...) принимает, что:

>>> ''.join([*plist[1:3], plist[5], plist[4], plist[7], plist[6]])
'on tap'
5
задан MSalters 10 February 2009 в 13:21
поделиться

8 ответов

Выполнение в отладчике изменяет библиотеку выделения памяти, пользовавшуюся на ту, которая делает намного больше проверки. Программа, которая делает только выделение памяти и освобождение, собирается пострадать намного больше, чем "нормальная" программа.

Редактируют только что попробовавший запущение Ваша программа в соответствии с VS, я получаю стек вызовов, который похож

ntdll.dll!_RtlpValidateHeapEntry@12()  + 0x117 bytes    
ntdll.dll!_RtlDebugFreeHeap@12()  + 0x97 bytes  
ntdll.dll!_RtlFreeHeapSlowly@12()  + 0x228bf bytes  
ntdll.dll!_RtlFreeHeap@12()  + 0x17646 bytes    
msvcr90d.dll!_free_base(void * pBlock=0x0061f6e8)  Line 109 + 0x13 bytes
msvcr90d.dll!_free_dbg_nolock(void * pUserData=0x0061f708, int nBlockUse=1)
msvcr90d.dll!_free_dbg(void * pUserData=0x0061f708, int nBlockUse=1) 
msvcr90d.dll!operator delete(void * pUserData=0x0061f708)
desc.exe!std::allocator<int>::deallocate(int * _Ptr=0x0061f708, unsigned int __formal=4)
desc.exe!std::vector<int,std::allocator<int> >::_Tidy()  Line 1134  C++

Который показывает функции отладки в ntdll.dll и используемом времени выполнения C.

18
ответ дан 18 December 2019 в 06:13
поделиться

Запущение программы с присоединенным отладчиком всегда медленнее, чем без.

Это должно быть вызвано VS, сцепляющимся в новые/удаленные вызовы и делающим больше проверки при присоединении - или библиотека времени выполнения использует IsDebuggerPresent API и делает вещи, отличающиеся в этом случае.

Можно легко попробовать это из Visual Studio, запустить программу с Отладкой->, Начинают Отлаживать, или Отладка-> Запускаются Без Отладки. Без отладки похож из командной строки, с точно той же конфигурацией сборки и исполняемым файлом.

3
ответ дан 18 December 2019 в 06:13
поделиться

"Куча" отладки автоматически включена при запуске программы в отладчике, в противоположность присоединению к уже под управлением программе с отладчиком.

Книга Усовершенствованный Windows Debugging Mario Hewardt и Daniel Pravat имеет некоторую достойную информацию о "куче" Windows, и оказывается, что глава по "куче" произошла на веб-сайте как демонстрационная глава.

Страница 281 имеет боковую панель о "Присоединении По сравнению с Запуском Процесса Под Отладчиком":

При запуске процесса под отладчиком диспетчер "кучи" изменяет все запросы, чтобы создать новую "кучу" и изменить флаги создания "кучи" для включения благоприятной для отладки "кучи" (если _NO_DEBUG_HEAP переменная среды не установлена на 1). В сравнении, присоединяя к уже рабочему процессу, "куча" в процессе была уже создана с помощью флагов создания "кучи" по умолчанию и не будет иметь благоприятного для отладки набора флагов (если явно не установлено приложением).

(Также: полусвязанный вопрос, где я отправил часть этого ответа прежде.)

3
ответ дан 18 December 2019 в 06:13
поделиться

Это - определенно HeapFree, это замедляет это, можно получить тот же эффект с программой ниже.

Передающие параметры как HEAP_NO_SERIALIZE к HeapFree не помогают также.

#include "stdafx.h"
#include <iostream>
#include <windows.h>

using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
HANDLE heap = HeapCreate(0, 0, 0);

void** pointers = new void*[50000];

int i = 0;
for (i = 0; i < 50000; ++i)
{
    pointers[i] = HeapAlloc(heap, 0, 4 * sizeof(int));
}

cout << i;
for (i = 49999; i >= 0; --i)
{
    HeapFree(heap, 0, pointers[i]);
}

cout << "!";

delete [] pointers;

HeapDestroy(heap);
}
2
ответ дан 18 December 2019 в 06:13
поделиться

Да, WTF действительно.

Вы знаете, что Ваш компилятор оптимизирует много тех вызовов функции путем встраивания их и затем далее оптимизирует код там для исключения чего-либо, что на самом деле не делает ничего, которое в случае векторов интервала будет означать: в значительной степени не много.

В режиме отладки не включено встраивание, потому что это сделало бы отладку ужасного.

Это - хороший пример того, как быстрый код C++ может действительно быть.

0
ответ дан 18 December 2019 в 06:13
поделиться

не имеет никакого смысла мне - присоединение отладчика к случайному двоичному файлу в нормальной конфигурации должно главным образом просто захватить прерывания точки останова (asm интервал 3, и т.д.).

-1
ответ дан 18 December 2019 в 06:13
поделиться

8 секунд?? Я попробовал то же в Режиме отладки. Не больше чем половина секунды я предполагаю. Вы уверены, что это - деструкторы?

К вашему сведению. Visual Studio 2008 SP1, Core 2 Duo 6 700 ЦП с 2 ГБ RAM.

0
ответ дан 18 December 2019 в 06:13
поделиться

http://www.symantec.com/connect/articles/windows-anti-debug-reference

прочтите разделы 2 «PEB! NtGlobalFlags» и 2 «Флаги кучи»

думают, что это может объяснить это ...


EDIT: добавлено решение

в ваш обработчик для CREATE_PROCESS_DEBUG_EVENT, добавьте следующее

// hack 'Load Configuration Directory' in exe header to point to a new block that specfies GlobalFlags 
IMAGE_DOS_HEADER dos_header;
ReadProcessMemory(cpdi.hProcess,cpdi.lpBaseOfImage,&dos_header,sizeof(IMAGE_DOS_HEADER),NULL);
IMAGE_OPTIONAL_HEADER32 pe_header;
ReadProcessMemory(cpdi.hProcess,(BYTE*)cpdi.lpBaseOfImage+dos_header.e_lfanew+4+sizeof(IMAGE_FILE_HEADER),&pe_header,offsetof(IMAGE_OPTIONAL_HEADER32,DataDirectory),NULL);
IMAGE_LOAD_CONFIG_DIRECTORY32 ilcd;
ZeroMemory(&ilcd,sizeof(ilcd));
ilcd.Size = 64; // not sizeof(ilcd), as 2000/XP didn't have SEHandler
ilcd.GlobalFlagsClear = 0xffffffff; // clear all flags.  this is as we don't want dbg heap
BYTE *p = (BYTE *)VirtualAllocEx(cpdi.hProcess,NULL,ilcd.Size,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
WriteProcessMemory(cpdi.hProcess,p,&ilcd,ilcd.Size,NULL);
BYTE *dde = (BYTE*)cpdi.lpBaseOfImage+dos_header.e_lfanew+4+sizeof(IMAGE_FILE_HEADER)+offsetof(IMAGE_OPTIONAL_HEADER32,DataDirectory)+sizeof(IMAGE_DATA_DIRECTORY)*IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
IMAGE_DATA_DIRECTORY temp;
temp.VirtualAddress = p-cpdi.lpBaseOfImage;
temp.Size = ilcd.Size;
DWORD oldprotect;
VirtualProtectEx(cpdi.hProcess,dde,sizeof(temp),PAGE_READWRITE,&oldprotect);
WriteProcessMemory(cpdi.hProcess,dde,&temp,sizeof(temp),NULL);
VirtualProtectEx(cpdi.hProcess,dde,sizeof(temp),oldprotect,&oldprotect);
1
ответ дан 18 December 2019 в 06:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: