Вы смешиваете списки и строки внутри другого списка, смешивая нарезку и индексацию. При нарезке создается список, индексирующий отдельный элемент.
Таким образом, рабочий код помещает только отдельных значений в список:
[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'
Выполнение в отладчике изменяет библиотеку выделения памяти, пользовавшуюся на ту, которая делает намного больше проверки. Программа, которая делает только выделение памяти и освобождение, собирается пострадать намного больше, чем "нормальная" программа.
Редактируют только что попробовавший запущение Ваша программа в соответствии с 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.
Запущение программы с присоединенным отладчиком всегда медленнее, чем без.
Это должно быть вызвано VS, сцепляющимся в новые/удаленные вызовы и делающим больше проверки при присоединении - или библиотека времени выполнения использует IsDebuggerPresent API и делает вещи, отличающиеся в этом случае.
Можно легко попробовать это из Visual Studio, запустить программу с Отладкой->, Начинают Отлаживать, или Отладка-> Запускаются Без Отладки. Без отладки похож из командной строки, с точно той же конфигурацией сборки и исполняемым файлом.
"Куча" отладки автоматически включена при запуске программы в отладчике, в противоположность присоединению к уже под управлением программе с отладчиком.
Книга Усовершенствованный Windows Debugging Mario Hewardt и Daniel Pravat имеет некоторую достойную информацию о "куче" Windows, и оказывается, что глава по "куче" произошла на веб-сайте как демонстрационная глава.
Страница 281 имеет боковую панель о "Присоединении По сравнению с Запуском Процесса Под Отладчиком":
При запуске процесса под отладчиком диспетчер "кучи" изменяет все запросы, чтобы создать новую "кучу" и изменить флаги создания "кучи" для включения благоприятной для отладки "кучи" (если _NO_DEBUG_HEAP переменная среды не установлена на 1). В сравнении, присоединяя к уже рабочему процессу, "куча" в процессе была уже создана с помощью флагов создания "кучи" по умолчанию и не будет иметь благоприятного для отладки набора флагов (если явно не установлено приложением).
(Также: полусвязанный вопрос, где я отправил часть этого ответа прежде.)
Это - определенно 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);
}
Да, WTF действительно.
Вы знаете, что Ваш компилятор оптимизирует много тех вызовов функции путем встраивания их и затем далее оптимизирует код там для исключения чего-либо, что на самом деле не делает ничего, которое в случае векторов интервала будет означать: в значительной степени не много.
В режиме отладки не включено встраивание, потому что это сделало бы отладку ужасного.
Это - хороший пример того, как быстрый код C++ может действительно быть.
не имеет никакого смысла мне - присоединение отладчика к случайному двоичному файлу в нормальной конфигурации должно главным образом просто захватить прерывания точки останова (asm интервал 3, и т.д.).
8 секунд?? Я попробовал то же в Режиме отладки. Не больше чем половина секунды я предполагаю. Вы уверены, что это - деструкторы?
К вашему сведению. Visual Studio 2008 SP1, Core 2 Duo 6 700 ЦП с 2 ГБ RAM.
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);