На собеседовании задали задачку:
есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
сколько я не ломаю голову — без привлечения внешних ресурсов очистить это список не поулчается — только бегать по нему от начала до конца.
тот кто задал вопрос — сказал что есть два варианта:
1. рекурсивно пройти по списку запоминая узлы, а потом удалить список. но здесь нарушение условия задачи — сохранение информации об адресах узлов это уже привлечение дополнительной памяти, так что этот вариант отпадает.
2. развернуть список и удалить его с головы. но здесь два момента — первый развернув список мы получаем новый объект и насколько корректно (формально) это решение — уже ставит под вопрос этот подход, но это не важно (практически задачу этот подход решает), вопрос два — как развернуть односвязанный список не прибегая к дополнительным ресурсам (памяти)?
сколько я голову не ломаю, но без дополнительных переменных — односвязанный список не перевернуть, надо по любому хранить в памяти адреса двух узлов.
собственно интересно, а есть ли фокус как обернуть односвязанный список без применения внешних ресурсов?
26.08.10 23:24: Перенесено модератором из 'Этюды для программистов'. Это уже безобразие, война остроконечников с остроначальниками... — Кодт
Здравствуйте, ssp_alex, Вы писали:
_>На собеседовании задали задачку: _>есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
_>сколько я голову не ломаю, но без дополнительных переменных — односвязанный список не перевернуть, надо по любому хранить в памяти адреса двух узлов.
Условие задачи позволяет использование памяти в объеме O(C). Запрет идет на объем памяти, измеряющийся некой неконстантной функцией от размера списка, т.е. O(n), O(Log n) и т.п.
Здравствуйте, ssp_alex, Вы писали:
_>2. развернуть список и удалить его с головы. но здесь два момента — первый развернув список мы получаем новый объект и насколько корректно (формально) это решение — уже ставит под вопрос этот подход, но это не важно (практически задачу этот подход решает), вопрос два — как развернуть односвязанный список не прибегая к дополнительным ресурсам (памяти)?
_>сколько я голову не ломаю, но без дополнительных переменных — односвязанный список не перевернуть, надо по любому хранить в памяти адреса двух узлов.
Без дополнительной памяти почти всегда означает «без дополнительной памяти по объёму зависящей от входных данных», то есть две переменные создать можно.
Здравствуйте, RomikT, Вы писали:
RT>Здравствуйте, ssp_alex, Вы писали:
_>>2. развернуть список и удалить его с головы. но здесь два момента — первый развернув список мы получаем новый объект и насколько корректно (формально) это решение — уже ставит под вопрос этот подход, но это не важно (практически задачу этот подход решает), вопрос два — как развернуть односвязанный список не прибегая к дополнительным ресурсам (памяти)?
_>>сколько я голову не ломаю, но без дополнительных переменных — односвязанный список не перевернуть, надо по любому хранить в памяти адреса двух узлов. RT>Без дополнительной памяти почти всегда означает «без дополнительной памяти по объёму зависящей от входных данных», то есть две переменные создать можно.
ключевое слово почти всегда, но, например, работая в рамках острого дефицита памяти две переменные это может быть много и это быть крайне критично. пример — микроконтроллеры, например для АБС или в состеме наведения спутника на цель.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, ssp_alex, Вы писали:
_>>На собеседовании задали задачку: _>>есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
_>>сколько я голову не ломаю, но без дополнительных переменных — односвязанный список не перевернуть, надо по любому хранить в памяти адреса двух узлов.
S>Условие задачи позволяет использование памяти в объеме O(C). Запрет идет на объем памяти, измеряющийся некой неконстантной функцией от размера списка, т.е. O(n), O(Log n) и т.п.
S>Т.е. на два узла память по-любому найдется.
да вот фиг знает что имелось ввиду под запретом на доп. память (вернее я выяснил, что имелось именно то что вы написали, но теперь уже поздно), но задачи похожие мне попадались и если в ТЗ сказанно нет доп памяти — занчит ее нет (не все пишут для PC и под NIX-ы, есть еще например микроконтроллеры и специализированные процессоры), а если в описи передаваемого оборудования есть виртуальные машины — то их надо передать на склад.
Re[3]: А как ты собирался список итерировать без доп памяти?
Здравствуйте, ssp_alex, Вы писали:
_>ключевое слово почти всегда, но, например, работая в рамках острого дефицита памяти две переменные это может быть много и это быть крайне критично. пример — микроконтроллеры, например для АБС или в состеме наведения спутника на цель.
Если пишешь на асме, то эти доп. переменные -- регистры. А если на языке высокого уровня, то это некая абстракция. Тот же С может положить их в регистр, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
_>ключевое слово почти всегда, но, например, работая в рамках острого дефицита памяти две переменные это может быть много и это быть крайне критично. пример — микроконтроллеры, например для АБС или в состеме наведения спутника на цель.
Это вы умозрительно или по опыту разработки АБС или "системы наведения спутника на цель" ? В риалтаймовых системах как две последние, нет такой вещи как "дефицит памяти", т.к. динамическое распределение памяти в реалтайме практически никогда недопустимо. А то, что память для алгоритма --- константная,
означает, что ее можно распределить во время компиляции. Другими словами --- отмазки это все.
_>>ключевое слово почти всегда, но, например, работая в рамках острого дефицита памяти две переменные это может быть много и это быть крайне критично. пример — микроконтроллеры, например для АБС или в состеме наведения спутника на цель.
dmz>Это вы умозрительно или по опыту разработки АБС или "системы наведения спутника на цель" ? В риалтаймовых системах как две последние, нет такой вещи как "дефицит памяти", т.к. динамическое распределение памяти в реалтайме практически никогда недопустимо. А то, что память для алгоритма --- константная, dmz>означает, что ее можно распределить во время компиляции. Другими словами --- отмазки это все.
угу. Посыпая голову пеплом, пошел повторять Мат.Часть.
_>1. рекурсивно пройти по списку запоминая узлы, а потом удалить список. но здесь нарушение условия задачи — сохранение информации об адресах узлов это уже привлечение дополнительной памяти, так что этот вариант отпадает.
зачем в этом случае запоминать что-то?
void free_list(elem){ // очистить список начиная с элемента elem, но в обратном порядкеif (el == NULL) // если конец спискаreturn; // выход
free_list(elem.next); // рекурсивно очищаем начиная с elem.next (след. элемент списка)
free(elem); // очищаем текущий
}
// где-то в main
free_list(list.head);
Здравствуйте, Muxa, Вы писали:
_>>1. рекурсивно пройти по списку запоминая узлы, а потом удалить список. но здесь нарушение условия задачи — сохранение информации об адресах узлов это уже привлечение дополнительной памяти, так что этот вариант отпадает. M>зачем в этом случае запоминать что-то? M>
M>void free_list(elem){ // очистить список начиная с элемента elem, но в обратном порядке
M> if (el == NULL) // если конец списка
M> return; // выход
M> free_list(elem.next); // рекурсивно очищаем начиная с elem.next (след. элемент списка)
M> free(elem); // очищаем текущий
M>}
M>// где-то в main
M> free_list(list.head);
M>
Внимание, вопрос! А стек для рекурсии у нас бесплатный, да?
К>А что тут думать. Реверсируем список по живому (т.е. меняем указатели в узлах списка) и затем коцаем с головы.
ну придумай как это сделать без доп. памяти.
мой вариант пока что требует дополнительно память под две переменные (длина списка — int, переменная цикла — int) + одна переменная на стэке — указатель на элемент списка.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
list_elem *next;
int *value;
};
#define SWAP(x, y)\
(x).value = (int *)((int)(x).value ^ (int)(y).value);\
(y).value = (int *)((int)(x).value ^ (int)(y).value);\
(x).value = (int *)((int)(x).value ^ (int)(y).value);
void free_elem(list_elem *e){
free(e->value);
}
void shift_list(list_elem *e){
while(e->next != NULL){
SWAP(*e, *(e->next));
e = e->next;
}
}
int main(int argc, char* argv[]) {
// формируем список
list_elem e5; e5.next = NULL; e5.value = (int*)malloc(sizeof(int)*1); *e5.value = 5;
list_elem e4; e4.next = &e5; e4.value = (int*)malloc(sizeof(int)*1); *e4.value = 4;
list_elem e3; e3.next = &e4; e3.value = (int*)malloc(sizeof(int)*1); *e3.value = 3;
list_elem e2; e2.next = &e3; e2.value = (int*)malloc(sizeof(int)*1); *e2.value = 2;
list_elem e1; e1.next = &e2; e1.value = (int*)malloc(sizeof(int)*1); *e1.value = 1;
list_elem e0; e0.next = &e1; e0.value = (int*)malloc(sizeof(int)*1); *e0.value = 0;
list_elem *e = &e0;
int n = 5; // ну, или находим сколько у нас элементов в списке (-1), если это заранее неизвестно
// магияwhile (e->next != NULL){
for (int i = 0; i < n; i++) // этот цикл поднимает последний элемент списка в начало
shift_list(e); // путем циклического сдвига списка
free_elem(e); // освобождаем поднятый элемент
e = e->next; // переходим к следующему
n--;
}
free_elem(e); // освобождаем послдений оставшийсяreturn 0;
}
Здравствуйте, Muxa, Вы писали:
К>>А что тут думать. Реверсируем список по живому (т.е. меняем указатели в узлах списка) и затем коцаем с головы. M>ну придумай как это сделать без доп. памяти.
"Без доп.памяти" — это, всё-таки, фикция.
С единичной памятью (два дополнительных указателя) — элементарно. За линейное время, в отличие от твоего квадратичного.
Здравствуйте, ssp_alex, Вы писали:
_>есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
Если именно так сформулировано, то очень просто
Замыкаем список в кольцо и уничтожаем элементы, начиная с последнего.
Я утверждаю, что это будет уничтожением, начиная с конца. Попробуйте возразить.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Я утверждаю, что это будет уничтожением, начиная с конца. Попробуйте возразить.
Зачем так париться-то?
Можно просто найти конец и уничтожить, а потом уничтожать себе как хочешь.
Только я бы сказал, что это решение соответствует формулировке "начав с конца", а не "начиная с конца"...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>Мда уж, кубический алгоритм, но обязательно — оптимизация макросами и xor-магией.
Не понятно, кстати, зачем всё это. Если уж мы нашли последний в списке, то можно бы его сразу грохнуть. Зачем тащить куда-то?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Можно просто найти конец и уничтожить, а потом уничтожать себе как хочешь.
Если у меня есть указатели на начало и конец, то я обойдусь одним проходом (собственно уничтожение). Тебе понадобится два прохода — первый проход в поисках предпоследнего элемента, второй -уничтожение.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если у меня есть указатели на начало и конец, то я обойдусь одним проходом (собственно уничтожение). Тебе понадобится два прохода — первый проход в поисках предпоследнего элемента, второй -уничтожение.
Ну и что?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>Если у меня есть указатели на начало и конец, то я обойдусь одним проходом (собственно уничтожение). Тебе понадобится два прохода — первый проход в поисках предпоследнего элемента, второй -уничтожение.
E>Ну и что?
Один проход всегда лучше, чем два. Несмотря на то, что в обоих случаях o(n)
>> #define SWAP(x, y)\ .>Мда уж, кубический алгоритм, но обязательно — оптимизация макросами и xor-магией.
предложи другой вариант без дополнительной памяти. даже без О(1).
.>>Мда уж, кубический алгоритм, но обязательно — оптимизация макросами и xor-магией. E>Не понятно, кстати, зачем всё это. Если уж мы нашли последний в списке, то можно бы его сразу грохнуть. Зачем тащить куда-то?
я забил на время (о нем ничего не сказано в условии), и пытался минимизировать затраты памяти. в иделе сведя их к 0.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Один проход всегда лучше, чем два. Несмотря на то, что в обоих случаях o(n)
Не всегда. Иногда "проще" лучше, чем "быстрее" Всё равно в задаче другое просили, на самом деле.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Muxa, Вы писали:
E>>Не понятно, кстати, зачем всё это. Если уж мы нашли последний в списке, то можно бы его сразу грохнуть. Зачем тащить куда-то? M>я забил на время (о нем ничего не сказано в условии), и пытался минимизировать затраты памяти. в иделе сведя их к 0.
Это я понял. Но я не понял, зачем свопы-то?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
On 14/08/10 13:39, Muxa wrote:
> .>Мда уж, кубический алгоритм, но обязательно — оптимизация макросами и > xor-магией. > предложи другой вариант без дополнительной памяти. даже без О(1).
Не понял. А чем вариант Кодта не устраивает?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Erop, Вы писали:
PD>>Один проход всегда лучше, чем два. Несмотря на то, что в обоих случаях o(n)
E>Не всегда. Иногда "проще" лучше, чем "быстрее"
On 14/08/10 19:43, Muxa wrote:
>> > предложи другой вариант без дополнительной памяти. *даже без О(1)*. > .>Не понял. А чем вариант Кодта не устраивает?
Не понял. Это как? Посмотри определение O-нотации.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Erop, Вы писали:
PD>>>Один проход всегда лучше, чем два. Несмотря на то, что в обоих случаях o(n)
E>>Не всегда. Иногда "проще" лучше, чем "быстрее"
PD>Хм, а чем твое решение лучше ?
Очевидно, что ничем. Просто концептуально проще. Например со списком можно работать не нарушая его инвариантов, то есть его обычными методами/функциями
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
.>Не понял. Это как? Посмотри определение O-нотации.
это значит не используя дополнитольно ни одного байта (костантного значения дополнительной памяти).
т.е. имея только список и работая тольо с ним.
On 14/08/10 22:04, Muxa wrote:
> .>Не понял. Это как? Посмотри определение O-нотации. > это значит не используя дополнитольно ни одного байта (костантного
Так это какое O?
> значения дополнительной памяти).
0 байт — тоже константное значение.
> т.е. имея только список и работая тольо с ним.
Приведи хоть один пример такого алгоритма.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
PD>>Хм, а чем твое решение лучше ? E>Очевидно, что ничем. Просто концептуально проще. Например со списком можно работать не нарушая его инвариантов, то есть его обычными методами/функциями
Уничтожить его надо, а не работать. После чего не останется ни списка, ни инвариантов
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Уничтожить его надо, а не работать. После чего не останется ни списка, ни инвариантов
Ну код разрушения тоже может быть обычным, а не каким-то особенным...
Скажем, если у списка есть методы delete_last и delete_first
то код может быть такой:
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Уничтожить его надо, а не работать. После чего не останется ни списка, ни инвариантов E>Ну код разрушения тоже может быть обычным, а не каким-то особенным...
О да, это весьма существенно. Написать 5 строчек , чтобы удалять иначе — это серьезная работа.
.>Так это какое O?
О-нотация.
.>0 байт — тоже константное значение.
хорошо, ноль дополнительных байт можно использовать. больше — нельзя.
.>Приведи хоть один пример такого алгоритма.
проход по списку до конца:
Здравствуйте, Muxa, Вы писали:
.>>0 байт — тоже константное значение. M>хорошо, ноль дополнительных байт можно использовать. больше — нельзя.
.>>Приведи хоть один пример такого алгоритма. M>проход по списку до конца: M>
S>Очевидно что e это внешняя по отношению к списку переменная.
Очевидно что е изначально это указатель на первый элемент списка.
А вашу фразу я не понял.
Здравствуйте, Muxa, Вы писали:
S>>Очевидно что e это внешняя по отношению к списку переменная. M>Очевидно что е изначально это указатель на первый элемент списка. M>А вашу фразу я не понял.
Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт. Это противоречит вашему требованию, которое я процитировал в предыдущем сообщении.
S>Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт.
... слово "дополнительно" везде выше в этой ветке какбэ намекаэ.
Здравствуйте, Muxa, Вы писали:
S>>Очевидно что e изначально не относится к списку и e занимает дополнительную память, отличную от 0-я байт. M>... слово "дополнительно" везде выше в этой ветке какбэ намекаэ.
Ну да, намекаэ на то, что эта дополнительная память не относится к памяти, отведенной под элементы списка.
Пройти по списку совсем без дополнительной памяти можно, но это будет деструктивное прохождение, т.к. как минимум одним элементом придется пожертвовать
S>Пройти по списку совсем без дополнительной памяти можно, но это будет деструктивное прохождение, т.к. как минимум одним элементом придется пожертвовать
да это понятно. у меня была идея "как бы сохранять" путь назад при помощи xor'ов где-либо (в next или value), что бы была возможность восстановить и "вернуться назад" по списку. но что-то ничего путного не придумалось.
Здравствуйте, Muxa, Вы писали:
M>это значит не используя дополнитольно ни одного байта (костантного значения дополнительной памяти). M>т.е. имея только список и работая тольо с ним.
Какие тогда операции над списком доступны?
У нас есть единственный регистр, в котором хранится адрес головного элемента.
И, видимо, есть процессор с набором инструкций, обходящихся ровно одним (вот этим самым) регистром.
Что это за инструкции?
// модель процессораint mem[];
int reg;
// операндыint& dst(bool m, bool r, int offset)
{
return m ? mem[ (r?reg:0)+offset ] : reg;
}
int src(bool m, bool r, int offset, int addend)
{
return m ? mem[(r?reg:0)+offset]+addend : r ? reg+addend : addend;
}
// возможна какая-нибудь двойная косвенностьint src2(bool r1, int a, bool r2, int b, int c) { return src(true,r2,src(true,r1,a,b),c)); }
// mem[mem[reg*r1+a]+reg*r2+b]+cint dst2(bool r1, int a, bool r2, int b) { return dst(true,r2,src(true,r1,a,b)); }
// mem[mem[reg*r1+a]+reg*r2+b]
// операцииvoid set(int& d, int s) { d = s; }
void add(int& d, int s) { d += s; }
void swap(int& d1, int& d2) { int t=d1; d1=d2; d2=t; }
int test(int s1, int s2) { return s1-s2; } // проверка на знак и ноль
Тогда поиск концевого узла, к примеру, выглядит так
Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое...
Был бы хоть один ещё регистр...
К>Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое...
все, я починил!
в общем исхитрился но уронить это очень просто. работает — вот и не трожь.
Здравствуйте, Muxa, Вы писали:
К>>Всё, что мы можем сделать — это исхитриться временно использовать содержимое узлов. И каким-то образом восстанавливать это содержимое... M>все, я починил! M>в общем исхитрился но уронить это очень просто. работает — вот и не трожь. M>
M> // первые 4 бита адреса используем для хранения информации необходимой для прохождения списка в обратном порядке
M> do {
M> ((list_elem *)(((int)e->next) & 0x00FFFFFF))->next = ...
M>}
S>Пишешь 4 бита, а используешь целый байт
да, да, да.
только подошел исправить, а тут уже подметили.
кстати, последние 2 бита адреса тоже можно приспособить, адреса-то выровнены по 4 байта.
On 15/08/10 21:18, Muxa wrote:
> все, я починил!
По-моему ты какой-то фигнёй страдаешь.
> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL);
Вот это не удастся посчитать без промежуточного регистра.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ssp_alex, Вы писали:
_>На собеседовании задали задачку: _>есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
Короче говоря, единственное нормальное решение задачи — инвертировать список, после чего пришибить от начала к концу. O(n) времени O(1) памяти. Любые другие решения являются больными. И вот закидайте меня помидорами — лучшего решения не существует в силу устройства этого вашего мира.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
M>>предложи другой вариант без дополнительной (!!!!!!111!1) памяти. даже без О(1). MS>Товарищ! Твой вариант тоже не отвечает критерию "без O(1)", ибо исполняемый код тоже занимает память.
блин, да вы чо? сговорились все что ли?
>> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL); .>Вот это не удастся посчитать без промежуточного регистра.
ммм, не вижу куда он (регистр) мог бы разходоваться.
Здравствуйте, Muxa, Вы писали:
>>> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL); .>>Вот это не удастся посчитать без промежуточного регистра. M>ммм, не вижу куда он (регистр) мог бы разходоваться.
Для хранения результатов логических умножений, как минимум.
S>Для хранения результатов логических умножений, как минимум.
я думая это компилятор лишнего наворачивает.
посмотрим во что скомпилировалась эта строка кода:
Здравствуйте, Muxa, Вы писали:
S>>Для хранения результатов логических умножений, как минимум. M>я думая это компилятор лишнего наворачивает.
O(x) оценивает количество алгоритмических ячеек, а не число регистров на конкретной архитектуре. Потому дело не в компиляторе и не в том, используется ли [ecx]. Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча).
скажи.
S>Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча).
но ведь это может быть таже самая ячейка где у нас до этого хранился операнд.
(если операнд далее не нужен, мы можем его спокойно перетереть).
согласен?
скажи.
S>>Для того чтобы воспользоваться результатом логического умножения в абстрактной архитектуре, требуется этот результат получить и сохранить в некоторой ячейке (неважно, регистр, стек или куча). M>но ведь это может быть таже самая ячейка где у нас до этого хранился операнд. M>(если операнд далее не нужен, мы можем его спокойно перетереть). M>согласен?
Ты говоришь о некоторой конкретной архитектуре. А в общем случае ячейка под операнд могла и не выделяться.
Что же касается конкретной архитектуры, то ячейка под операнд — это уже дополнительная память по отношению к списку.
Хорош извращаться. Так академические задачи не решают.
Здравствуйте, ., Вы писали:
.>По-моему ты какой-то фигнёй страдаешь.
Естественно :) Только не "страдаешь", а "наслаждаешься" :)
>> }while(e->next != NULL&& ((int)((((list_elem *)(((int)e->next)& 0x00FFFFFF))->next))& 0x00FFFFFF) != NULL); .>Вот это не удастся посчитать без промежуточного регистра.
Это смотря какое АЛУ.
Мы же можем сделать специальный процессор, в которм эта страхолюная конструкция реализована аппаратно.
Ячейка памяти — для хранения данных между шагами — будет одна (и будет содержать e), а все промежуточные данные внутри выражения — не более, чем состояния шин.
Правда, память нам потребуется трёхпортовая.
On 16/08/10 13:05, Кодт wrote:
> Это смотря какое АЛУ. > Мы же можем сделать специальный процессор, в которм эта страхолюная > конструкция реализована аппаратно. > Ячейка памяти — для хранения данных между шагами — будет одна (и будет > содержать e), а все промежуточные данные внутри выражения — не более, > чем состояния шин. > Правда, память нам потребуется трёхпортовая.
А если сделать специальный процессор для этой задачи, с единственной командой "очистить список с конца"...
Вообще говоря, от вычислителя зависит алгоритмическая сложность... И линейные алгоритмы вполне могут вдруг становиться квадратными.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
К>Естественно Только не "страдаешь", а "наслаждаешься"
ну, хоть кто-то меня понимает. К>...
я тут глянул на ассемблерный код, в который компилируется моя бодяга.
регистров там конечно много использовано. я его модифицировал, оставив только два регистра eax и edx, плюс осталась какая-то непонятная e (видимо та что из сишного кода (указатель на элемент), я так и не понял что это и где хранится)
Здравствуйте, ., Вы писали:
.>А если сделать специальный процессор для этой задачи, с единственной командой "очистить список с конца"... :)
Ну, перетащим решение в микрокод.
Оно всё равно будет не менее O(N) по времени, и, вероятно, таки потребует дополнительную память данных.
.>Вообще говоря, от вычислителя зависит алгоритмическая сложность... И линейные алгоритмы вполне могут вдруг становиться квадратными.
Максимум, тут будет фигурировать разрядность.
То есть, *log(N), если адресная арифметика сделана в big-int.
Хотя, *N или даже *N², если это машина Тьюринга...
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>О да, это весьма существенно. Написать 5 строчек , чтобы удалять иначе — это серьезная работа.
Дело не в пяти строчках, а в чистоте подхода. Если ты что-то где-то делаешь не так, как обычно, то у тебя должна быть на это какая-то веская причина, которую ты там же и должен указать в комментарии.
В частности, если ты на время работы метода хочешь нарушить инвариант класса, хотя этого очевидно можно не делать, то тоже должна быть причина. Или ты считаешь нарушение инварианта класса на время работы метода нормой?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>О да, это весьма существенно. Написать 5 строчек , чтобы удалять иначе — это серьезная работа. E>Дело не в пяти строчках, а в чистоте подхода.
О да!
>Если ты что-то где-то делаешь не так, как обычно
Я многое делаю не так как обычно
>, то у тебя должна быть на это какая-то веская причина, которую ты там же и должен указать в комментарии.
Причина обычно есть, в комментариях иногда пишу.
E>В частности, если ты на время работы метода хочешь нарушить инвариант класса, хотя этого очевидно можно не делать, то тоже должна быть причина. Или ты считаешь нарушение инварианта класса на время работы метода нормой?
Я считаю нормой все, что мне в данный момент подходит. Даже если это противоречить третьему каноническому правилу, второму безусловному табу, четвертому инварианту и мнению святых апостолов.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Я считаю нормой все, что мне в данный момент подходит. Даже если это противоречить третьему каноническому правилу, второму безусловному табу, четвертому инварианту и мнению святых апостолов.
При чём тут святые апостолы? Для успешной работы в команде надо стремиться писать максимально простой и понятный и однообразный код. А не впендриваться то так то этак
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>При чём тут святые апостолы? Для успешной работы в команде надо стремиться писать максимально простой и понятный и однообразный код. А не впендриваться то так то этак
Апостолами даны заповеди написания максимально простого и понятного кода.
Увы. я атеист . Так что гореть мне в геенне.
Если без шуток. Максимально простой и понятный код — это одно из неплохих требований к коду. Но не более, чем одно из. И если есть некие соображения, побуждающие написать не очень простой и совсем плохо понятный код, получив при этом серьезный профит в другой области — я без сожаления пожертвую простотой и понятностью.
Здравствуйте, Erop, Вы писали:
E>Или ты считаешь нарушение инварианта класса на время работы метода нормой?
Конечно норма, коль практически все операции внутри метода императивны и не атомарны. Главное, чтобы объект был валиден на выходе из метода или в момент вызова других неприватных методов.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если без шуток. Максимально простой и понятный код — это одно из неплохих требований к коду. Но не более, чем одно из. И если есть некие соображения, побуждающие написать не очень простой и совсем плохо понятный код, получив при этом серьезный профит в другой области — я без сожаления пожертвую простотой и понятностью.
Дык твоё решение ничем не лучше, а код хуже
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Дык твоё решение ничем не лучше, а код хуже
Ну если ты считаешь, что однопроходной алгоритм ничем не лучше двухпроходного, причем в ситуации, когда два прохода попросту не нужны, тогда конечно. У меня на сей счет иное мнение.
Здравствуйте, Erop, Вы писали:
E>Или ты считаешь нарушение инварианта класса на время работы метода нормой?
А кстати, как ты относишься к тому, что во время работы функции вставки или удаления в списке он вообще на некоторое время становится невалиден ?
// insert at the end
ListElement * tmp = new ListElement;
tmp->data = ...
tmp->next = NULL;
end->next = tmp;
// и вот сейчас список совсем невалиден. Указатель на конец показывает совсем не на конец.
// исправляемся
end = tmp;
// и он опять валиден.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ну если ты считаешь, что однопроходной алгоритм ничем не лучше двухпроходного, причем в ситуации, когда два прохода попросту не нужны, тогда конечно. У меня на сей счет иное мнение.
А почему ты считаешь свой алгоритм "однопроходным"?
Он у тебя состоит из двух фаз: найти конец списка и закольцевать список; удалять элементы кольцевого списка вплоть до полного его исчерпания.
У меня алгоритм состоит тоже из двух фаз: найти конец списка и разрушить его; удалять элементы из начала списка вплоть до его исчерпания.
Честно говоря, я не вижу каких-то существенных отличий, кроме того, что в твоём случае надо нарушать инвариант списка.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А кстати, как ты относишься к тому, что во время работы функции вставки или удаления в списке он вообще на некоторое время становится невалиден ?
Либо, как к неизбежному злу, либо, как в случае односвязанного списка, как к лошеству автора
PD>
PD>// и вот сейчас список совсем невалиден. Указатель на конец показывает совсем не на конец.
PD>// исправляемся
PD>end = tmp;
PD>// и он опять валиден.
PD>
Интересно, зачем в односвязанном списке нужен этот указатель?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А почему ты считаешь свой алгоритм "однопроходным"?
E>Он у тебя состоит из двух фаз: найти конец списка и закольцевать список; удалять элементы кольцевого списка вплоть до полного его исчерпания. E>У меня алгоритм состоит тоже из двух фаз: найти конец списка и разрушить его; удалять элементы из начала списка вплоть до его исчерпания.
Ничего подобного. В моей реализации однонаправленного списка я всегда храню указатель на конец списка.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ничего подобного. В моей реализации однонаправленного списка я всегда храню указатель на конец списка.
И как он поможет тебе его удалить первым? Или ты хранишь указатель на предпоследний элемент?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ничего подобного. В моей реализации однонаправленного списка я всегда храню указатель на конец списка.
Так и в моём алгоритме тогда искать не нужно
В общем я так тебя понял, что ты предложил разрушить последний элемент списка, потом первый, второй и т. д. до исчерпания списка.
Вот я утверждаю, что это можно сделать прямо, не создавая закольцованных списков
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>А кстати, как ты относишься к тому, что во время работы функции вставки или удаления в списке он вообще на некоторое время становится невалиден ? E>Либо, как к неизбежному злу, либо, как в случае односвязанного списка, как к лошеству автора
Ну-ну. Ты это Вирту скажи, я когда-то впервые осваивал списки по его книге, там как раз это решение и приводилось.
PD>>end = tmp; PD>>// и он опять валиден. PD>>[/ccode] E>Интересно, зачем в односвязанном списке нужен этот указатель?
Чтобы вставлять в конец списка без его прохода . Например, реализация очереди на базе однонаправленного списка. Удалять из конца невозможно, поэтому удалять будем из начала, а добавлять в конец списка. И если при добавлении в конец ты будешь каждый раз проходить весь список — ты превратишь O(1) в O(N).
Впрочем, и без очереди тоже. Вот как раз сейчас у меня задача, в которой новые элементы добавляются только в конец (и никогда никакие элементы не удаляются, потом список уничтожается целиком). И как же мне его реализовать без того, чтобы хранить указатель на конец ? А расходы при этом нулевые — один указатель.
Здравствуйте, Erop, Вы писали:
PD>>Ничего подобного. В моей реализации однонаправленного списка я всегда храню указатель на конец списка.
E>И как он поможет тебе его удалить первым? Или ты хранишь указатель на предпоследний элемент?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Впрочем, и без очереди тоже. Вот как раз сейчас у меня задача, в которой новые элементы добавляются только в конец (и никогда никакие элементы не удаляются, потом список уничтожается целиком). И как же мне его реализовать без того, чтобы хранить указатель на конец ? А расходы при этом нулевые — один указатель.
В такой задаче да, выгодно хранить. Ещё выгоднее, и логичнее, к тому же, хранить просто узел, после которого ты вставляешь элементы. Тогда "точку роста" можно в любом месте иметь
А у Вирта, вроде как, было немного не так. Там в качестве итератора элемента списка использовался, помнится, указатель на элемент перед тем, на который мы хотим указать. А в начале списка был один недоступный служебный элемент.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>И как он поможет тебе его удалить первым? Или ты хранишь указатель на предпоследний элемент? PD>А мне вовсе и не надо его удалять.
Мы всё ещё про задачу "разрушить элементы односвязанного списка, начиная с конца" или о чём-то другом?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>Вот я утверждаю, что это можно сделать прямо, не создавая закольцованных списков
PD>Расскажи, как это сделать однопроходным алгоритмом, не храня указатель на конец и не замыкая.
Однопроходность зависит от того, что ты хранишь в списке. В твоём варианте (с указтелем на последний элемент) однопроходно нельзя, не важно кольцуя или нет.
Замыкать для этого в любом случае не надо.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>Впрочем, и без очереди тоже. Вот как раз сейчас у меня задача, в которой новые элементы добавляются только в конец (и никогда никакие элементы не удаляются, потом список уничтожается целиком). И как же мне его реализовать без того, чтобы хранить указатель на конец ? А расходы при этом нулевые — один указатель.
E>В такой задаче да, выгодно хранить. Ещё выгоднее, и логичнее, к тому же, хранить просто узел, после которого ты вставляешь элементы. Тогда "точку роста" можно в любом месте иметь
Не знаю я, что за такой узел, и по каким критериям его иметь. Если есть такой критерий — пожалуйста.
E>А у Вирта, вроде как, было немного не так. Там в качестве итератора элемента списка использовался, помнится, указатель на элемент перед тем, на который мы хотим указать. А в начале списка был один недоступный служебный элемент.
Это — самый простой способ построения списка. Но при этом
полученный порядок элементов обратен порядку их «поступ-
«поступления». В некоторых случаях это нежелательно; следова-
следовательно, новые элементы должны добавляться в конец списка.
Хотя конец легко найти проходом по списку, такой непосред-
непосредственный подход потребовал бы затрат, которых просто избе-
избежать, используя вторую ссылку q, которая всегда указывает
на последний элемент. Такой метод применяется, например,
в программе 4.4, формирующей перекрестные ссылки на за-
заданный текст. Недостаток такого метода состоит в том, что
первый включаемый элемент приходится обрабатывать иначе,
чем остальные.
E>>>И как он поможет тебе его удалить первым? Или ты хранишь указатель на предпоследний элемент? PD>>А мне вовсе и не надо его удалять. E> E>Мы всё ещё про задачу "разрушить элементы односвязанного списка, начиная с конца" или о чём-то другом?
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>В такой задаче да, выгодно хранить. Ещё выгоднее, и логичнее, к тому же, хранить просто узел, после которого ты вставляешь элементы. Тогда "точку роста" можно в любом месте иметь PD>Не знаю я, что за такой узел, и по каким критериям его иметь. Если есть такой критерий — пожалуйста.
Ну вот в твоей задаче это последний добавленный...
PD>первый включаемый элемент приходится обрабатывать иначе, PD>чем остальные.
Вот для этого как раз у Вирта в начале списка был невидимый пользователям элемент...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>А мне вовсе и не надо его удалять. E>> E>>Мы всё ещё про задачу "разрушить элементы односвязанного списка, начиная с конца" или о чём-то другом?
PD>Да , про нее (в моей "интерпретации"
А почему, тогда, тебе не надо удалять последний элемент?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>Расскажи, как это сделать однопроходным алгоритмом, не храня указатель на конец и не замыкая. E>Однопроходность зависит от того, что ты хранишь в списке.
Это что-то новое. Почему ? На удаление того, что там хранится, есть деструктор ListElement, он должен знать, как там удалять.
>В твоём варианте (с указтелем на последний элемент) однопроходно нельзя, не важно кольцуя или нет.
Вирта почитай. Там есть прием для удаления текущего элемента.
//////////////////////////////////////////////////
Труднее удалить сам указанный элемент (а не следующий
за ним), поскольку мы сталкиваемся с той же проблемой,
что и при включении перед р\: возврат к элементу, который
Рис. 4.9. Удаление из списка и включение в другой список.
предшествует указанному, невозможен. Но можно удалить
последующий элемент, предварительно переслав его значение
ближе к началу списка. Это довольно очевидный и простой
прием, но его можно применить только в случае, когда у р\
есть последующий элемент, т. е. он не является последним
элементом списка.
//////////////////////////////////////////////////
А в циклическом списке как раз и нет последнего в этом смысле элемента
E>Замыкать для этого в любом случае не надо.
Здравствуйте, Erop, Вы писали:
E>>>В такой задаче да, выгодно хранить. Ещё выгоднее, и логичнее, к тому же, хранить просто узел, после которого ты вставляешь элементы. Тогда "точку роста" можно в любом месте иметь PD>>Не знаю я, что за такой узел, и по каким критериям его иметь. Если есть такой критерий — пожалуйста. E>Ну вот в твоей задаче это последний добавленный...
Последний — вполне четкий критерий независимо от задачи.
E>Вот для этого как раз у Вирта в начале списка был невидимый пользователям элемент...
Ты мне будешь про списки с барьером и с начальным элементом рассказывать ? Поверь, после примерно 10 лет чтения студентам этого курса я о них что-то знаю.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вирта почитай. Там есть прием для удаления текущего элемента.
Это удаление следующего элемента + копирование его данных в текущий. Являются ли эти действия эквивалентными -- вопрос спорный. Я, например, так не считаю
PD>Ну так напиши код.
Так я вроде как уже писал
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
>>В твоём варианте (с указтелем на последний элемент) однопроходно нельзя, не важно кольцуя или нет.
PD>Вирта почитай. Там есть прием для удаления текущего элемента.
Кстати, если ты считаешь, что разрушение копии эквивалентно разрушению оригинала, то ты можешь просто обменять содержимое начала и конца списка, а потом ужо разрушать с начала и не париться
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Вирта почитай. Там есть прием для удаления текущего элемента. E>Это удаление следующего элемента + копирование его данных в текущий. Являются ли эти действия эквивалентными -- вопрос спорный. Я, например, так не считаю
Доказательства в студию.
PD>>Ну так напиши код.
E>Так я вроде как уже писал
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ты мне будешь про списки с барьером и с начальным элементом рассказывать ? Поверь, после примерно 10 лет чтения студентам этого курса я о них что-то знаю.
Тем больше меня удивляет то, что ты тут пишешь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PE>>Это удаление следующего элемента + копирование его данных в текущий. Являются ли эти действия эквивалентными -- вопрос спорный. Я, например, так не считаю
PD>Доказательства в студию.
Доказательства чего?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Кстати, если ты считаешь, что разрушение копии эквивалентно разрушению оригинала, то ты можешь просто обменять содержимое начала и конца списка, а потом ужо разрушать с начала и не париться
Можно и так. Только делать это придется каждый раз, иначе ты после последнего удалишь второй, а не первый.
Здравствуйте, Erop, Вы писали:
PD>>Ты мне будешь про списки с барьером и с начальным элементом рассказывать ? Поверь, после примерно 10 лет чтения студентам этого курса я о них что-то знаю.
E>Тем больше меня удивляет то, что ты тут пишешь
Меня тоже. Если у тебя уж цитаты из Вирта вызывают улыбку, то надо все же аргументы приводить. Их нет, есть лишь одни слова.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Можно и так. Только делать это придется каждый раз, иначе ты после последнего удалишь второй, а не первый.
Ну и что?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PE>>>Это удаление следующего элемента + копирование его данных в текущий. Являются ли эти действия эквивалентными -- вопрос спорный. Я, например, так не считаю
PD>>Доказательства в студию.
E>Доказательства чего?
Здравствуйте, Erop, Вы писали:
PD>>Можно и так. Только делать это придется каждый раз, иначе ты после последнего удалишь второй, а не первый.
E>Ну и что?
Ничего. Вполне допустимый способ — если, конечно, пренебречь тем, что для того, чтобы к нему добраться , тебе сначала потребовалось соорудить двухпроходной алгоритм, потом отрицать необходимость хранить конец списка, потом поставить под сомнение способ Вирта по удалению элемента, а потом принять этот способ , предложив не совсем верное, но близкое к верному решение, базирующееся на методе, о котором пишет Вирт и на хранении указателя на конец
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ничего. Вполне допустимый способ — если, конечно, пренебречь тем, что для того, чтобы к нему добраться , тебе сначала потребовалось соорудить двухпроходной алгоритм, потом отрицать необходимость хранить конец списка, потом поставить под сомнение способ Вирта по удалению элемента,
Ничего я не принимал и не сооружал. Я просто пытаюсь показать тебе, что закольцовывать список никогда не надо. Если ты считаешь, что разрушение копии это тоже, что и разрушение оригинала, то можно менять начало и конец. Если не считаешь, то надо удалять конец, а потом что угодно, например с начала.
Если у тебя есть сразу возможность удалить последний элемент списка без поиска, то можешь удалить его и дальше делать что хочешь, если не можешь удалить без поиска, то не можешь, значит надо найти, удалить, а потом делать что хочешь ну и так далее.
В общем тезис состоит в том, что закольцовывать список никогда не надо
PD>а потом принять этот способ , предложив не совсем верное, но близкое к верному решение, базирующееся на методе, о котором пишет Вирт и на хранении указателя на конец
Я ещё раз намекаю тебе, что уничтожение элемента списка, и уничтожение элемента списка с теми же данными -- это разные операции.
Например, представь себе, что аллокатору, на котором выделены элементы не всё равно в каком порядке их освобождают, или, например, что данные вообще нельзя скопировать. Например, что это открытые файлы
Кроме того, я ещё всё же думаю, что ты в целом некорректно интерпретируешь условие задачи
PD>Век живи — век учись
Полезный совет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А если не секрет — смайлик по отношению ко мне или к Вирту ? Я вроде тут вообще ничего не сказал
Смешно то, как ты позорно изворачиваешься, не желая признать того, что закольцовывать список в этой задаче никогда не надо.
Брякнул глупость и никак не признаешь этого очевидного факта
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[28]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PE>>>>Это удаление следующего элемента + копирование его данных в текущий. Являются ли эти действия эквивалентными -- вопрос спорный. Я, например, так не считаю PD>>>Доказательства в студию.
Интересно, какие тебе нужны доказательства того, что я так не считаю?
Если тебе интересно почему я так не считаю, то я могу пояснить.
Во-первых, далеко не все объекты можно копировать.
Во-вторых, могут быть какие-то ссылки на элементы списка снаружи. И деструкторы элементов могут их откуда-то вымарывать, где-то что-то логгироватьи т. д.
В-третьих, вообще задача "разрушить в таком-то порядке" обычно обозначает либо то, что у деструкторов есть побочные эффекты либо то, что аллокатору не всё равно в каком порядке ему отдают память.
Во всех этих случаях легко может оказаться, что разрушение копии не эквивалентно разрушению оригинала...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Например, представь себе, что аллокатору, на котором выделены элементы не всё равно в каком порядке их освобождают, или, например, что данные вообще нельзя скопировать. Например, что это открытые файлы
Ай-яй -яй. А на открытые файлы есть, между прочим, дескрипторы, которые вполне можно копировать. Файл при этом копировать совсем не надо.
И что за проблемы тут возникнут при удалении списка ? Хоть с закрытием файлов, хоть без.
E>Кроме того, я ещё всё же думаю, что ты в целом некорректно интерпретируешь условие задачи
Разумеется. Я об этом с самого начала сказал
PD>>Век живи — век учись E>Полезный совет
Вот и прими его во внимание, и пиши, сначала подумав.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
E>Смешно то, как ты позорно изворачиваешься, не желая признать того, что закольцовывать список в этой задаче никогда не надо. E>Брякнул глупость и никак не признаешь этого очевидного факта
Скорее уж именно ты тут изворачиваешься. Поставил смайлик Вирту , а теперь не знаешь, как из этой ситуации выйти. Вполне достаточно того, что ты в этой подветке пытаешься перевести разговор на меня, хотя я задал тебе четкий вопрос — что тебя заставило улыбнуться в тексте из Вирта. Это и называется изворачиваться.
With best regards
Pavel Dvorkin
Re[29]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Erop, Вы писали:
E>Во-вторых, могут быть какие-то ссылки на элементы списка снаружи. И деструкторы элементов могут их откуда-то вымарывать, где-то что-то логгироватьи т. д.
Если же есть ссылки на элементы списка снаружи, то интересно было бы знать, куда они будут показывать после уничтожения списка любым способом ? . Зарапортовались, батенька.
With best regards
Pavel Dvorkin
Re[30]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 12:31, Pavel Dvorkin wrote:
> Если же есть ссылки на элементы списка снаружи, то интересно было бы > знать, куда они будут показывать после уничтожения списка *любым > способом* ? . Зарапортовались, батенька.
Так он и пишет, что деструктор элемента может что-то делать с этими ссылками, например, посылать сообщение: "я удаляюсь, забудьте про меня".
Понятно, что предложенный тобою алгоритм использовать можно во многих ситуациях, но он не эквивалентен, о чём и говорит Ероп.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[31]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, ., Вы писали:
.>Так он и пишет, что деструктор элемента может что-то делать с этими ссылками, например, посылать сообщение: "я удаляюсь, забудьте про меня".
Пишет он нечто иное
E>Во-вторых, могут быть какие-то ссылки на элементы списка снаружи
То есть снаружи есть ссылки на уничтожаемые элементы. И деструктор зачем-то разыскивает эти ссылки где-то снаружи, чтобы по ним добраться к элементу, который он сейчас уничтожает и послать ему сообщение ?
Я бы понял, если бы, наоборот, в элементе была ссылка во внешний мир, и при уничтожении надо эту ссылку задействовать. Но в этой ситуации нет ничего особенного. В деструкторе надо уничтожить блок памяти, закрыть файл и послать сообщение по внешней ссылке...
With best regards
Pavel Dvorkin
Re[32]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 14:30, Pavel Dvorkin wrote:
> То есть снаружи есть ссылки на уничтожаемые элементы. И деструктор > зачем-то разыскивает эти ссылки где-то снаружи, чтобы по ним добраться к > элементу, который он сейчас уничтожает и послать ему сообщение ?
Ээ.. Не совсем так, но примерно в этом духе. Типичная ситуация — у элемента есть множество подписчиков. В деструкторе все подписчики уведомляются об уничтожении.
Кто такой Elem ? Судя по вызову s->onDestroy(this); тут должен быть не Elem,а ListElem , так ? А если так — зачем хранить ссылку на ListElem, если она передается в эти методы ? Но это так, к слову.
.>Что делают подписчики — неизвестно. Вероятно могут хранить ссылку на ListElem.
Вообще-то могут, верно.
.>Так что не всегда можно тупо переместить объект в памяти и сказать, мол, шо так и былО.
В общем случае — да. Но это уже не список объектов, а некая иная структура. Более того, ситуация, когда извне списка имеются указатели на его ListElem — мягко говоря, не очень хорошая. Тут и без всяких пересылок до неприятностей один шаг. В этом случае надо вообще-то заводить некий новый класс, инкапсулирующий в себе и List, и эти Subscriber'ы. А это уже иная песня.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Скорее уж именно ты тут изворачиваешься. Поставил смайлик Вирту , а теперь не знаешь, как из этой ситуации выйти. Вполне достаточно того, что ты в этой подветке пытаешься перевести разговор на меня, хотя я задал тебе четкий вопрос — что тебя заставило улыбнуться в тексте из Вирта. Это и называется изворачиваться.
Я тебе чётко ответил что -- невтемность этого текста в обсуждаемой теме
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Скорее уж именно ты тут изворачиваешься. Поставил смайлик Вирту , а теперь не знаешь, как из этой ситуации выйти. Вполне достаточно того, что ты в этой подветке пытаешься перевести разговор на меня, хотя я задал тебе четкий вопрос — что тебя заставило улыбнуться в тексте из Вирта. Это и называется изворачиваться.
E>Я тебе чётко ответил что -- невтемность этого текста в обсуждаемой теме
Ну да, конечно. Что же можно еще сказать
Ладно, я думаю, хватит.
With best regards
Pavel Dvorkin
Re[30]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Erop, Вы писали:
E>>Во-вторых, могут быть какие-то ссылки на элементы списка снаружи. И деструкторы элементов могут их откуда-то вымарывать, где-то что-то логгироватьи т. д.
PD>Если же есть ссылки на элементы списка снаружи, то интересно было бы знать, куда они будут показывать после уничтожения списка любым способом ? . Зарапортовались, батенька.
Например, деструкторы могут сниматьобъекты с регистрации. При этом порядок съема с регистрации может быть важен
Для того, чтобы понимать эквивалентно ли разрушение объекта и его копии, надо понимать, откуда вообще возникает требование на порядок разрушения элементво списка. Если оно возникает непонятно откуда, то должно трактоваться максимально прямо, то есть как разрушение именно узлов, производимое в нужном порядке, без всяких трюков с копированием...
Но это всего лишь обсужденеи того, как интерпретировать условие. Можно и так и так, но как не интерпретируй, всё равно закольцовывать список нет никакой нужды.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
PD>Ай-яй -яй. А на открытые файлы есть, между прочим, дескрипторы, которые вполне можно копировать. Файл при этом копировать совсем не надо.
Ай-ай говоришь? А если это не FILE*, а CFile, например?
Ты воообще можешь представить себе некопируемый объект какой-нибудь? Или у тебя таки все объекты имеют семантику значения?
PD>И что за проблемы тут возникнут при удалении списка ? Хоть с закрытием файлов, хоть без.
Ну как же. Пусть деструктор узла закрывает файл. При применении схемы с копированием некоторые будут закрыты дважды, а некоторые ни разу. Можно, конечно, при присваивании, предыдущий закрывать, но тогда всё равно некоторые файлы будут закрыты по нескольку раз...
Правда копирование можно заменить на обмен. Но, к сожалению, даже менять можно не все объекты...
PD>Вот и прими его во внимание, и пиши, сначала подумав.
И ты тоже %)~
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Ай-ай говоришь? А если это не FILE*, а CFile, например?
Там нет копирования при Виртовской операции. Там побитовая пересылка.
E>Ты воообще можешь представить себе некопируемый объект какой-нибудь? Или у тебя таки все объекты имеют семантику значения?
PD>>
PD>>И что за проблемы тут возникнут при удалении списка ? Хоть с закрытием файлов, хоть без. E>Ну как же. Пусть деструктор узла закрывает файл. При применении схемы с копированием некоторые будут закрыты дважды, а некоторые ни разу.
Еще раз, внятно. FILE* file из текущего элемента обменивается с FILE* file из следующего элемента. Побитовый обмен. Никакие деструкторы тут не вызываются. После чего все идет как идет.
E>Правда копирование можно заменить на обмен. Но, к сожалению, даже менять можно не все объекты...
Пример, пожалуйста. Наследование не предлагать — все элементы списка имеют всегда один и тот же тип.
With best regards
Pavel Dvorkin
Re[34]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 15:48, Pavel Dvorkin wrote:
> Кто такой Elem ? Судя по вызову s->onDestroy(this); тут должен быть не > Elem,а ListElem , так ?
Верно, просто опечатка.
>если так — зачем хранить ссылку на ListElem, > если она передается в эти методы ? Но это так, к слову.
Для удобства. Во многих случаях позволяет создавать один экземпляр ElemSubsriber:
> В общем случае — да. Но это уже не список объектов, а некая иная > структура. Более того, ситуация, когда извне списка имеются указатели на > его ListElem — мягко говоря, не очень хорошая. Тут и без всяких > пересылок до неприятностей один шаг. В этом случае надо вообще-то > заводить некий новый класс, инкапсулирующий в себе и List, и эти > Subscriber'ы. А это уже иная песня.
В общем-то одна из полезнейших фич связного списка в отличие от всяких массивов, что ссылки на его элементы не инвалидируются при его модификациях.
И называется это non-intrusive lists, вещь зело полезная и довольно распространённая.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[32]: Не надо прикрывать Виртом свою некомпетентность ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Там нет копирования при Виртовской операции. Там побитовая пересылка.
Бинго! Вот он самый безопасный паттерн! Кстати, про Вирта, как эта самая побитовая пересылка выглядит на паскале?
И, прости, а что происходит с оригиналом пересылки-то? Он разрушается или как? И кто зовёт деструктор того объекта, который затирают.
PD>Еще раз, внятно. FILE* file из текущего элемента обменивается с FILE* file из следующего элемента. Побитовый обмен. Никакие деструкторы тут не вызываются. После чего все идет как идет.
Про побитовый обмен -- это уже ново. До этого, у Вирта, например, речь шла о затирании одного другим вроде бы.
Ну да ладно, Вирт-то понятно что имел в виду, а что имеешь в виду ты -- не совсем понятно
E>>Правда копирование можно заменить на обмен. Но, к сожалению, даже менять можно не все объекты... PD>Пример, пожалуйста. Наследование не предлагать — все элементы списка имеют всегда один и тот же тип.
Почему это все элементы списка всегда имеют один и тот же тип? Скажем список контролов окна чем плох?
Ну а пример простой очень. Объект, который где-то зарегистрирован вне списка.
Ну, например, буфер для асинхронного получения данных из трубы. У меня список таких буферов. В деструкторах они себя разрегистрируют, и коннекшен закрывают. Ваши действия, уважаемый?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[32]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, ., Вы писали:
PD>Я бы понял, если бы, наоборот, в элементе была ссылка во внешний мир, и при уничтожении надо эту ссылку задействовать. Но в этой ситуации нет ничего особенного. В деструкторе надо уничтожить блок памяти, закрыть файл и послать сообщение по внешней ссылке...
Никогда слушателя сообщения в деструкторе не снимал?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[34]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В общем случае — да. Но это уже не список объектов, а некая иная структура. Более того, ситуация, когда извне списка имеются указатели на его ListElem — мягко говоря, не очень хорошая. Тут и без всяких пересылок до неприятностей один шаг. В этом случае надо вообще-то заводить некий новый класс, инкапсулирующий в себе и List, и эти Subscriber'ы. А это уже иная песня.
Зачем?
Вот представь себе, что есть список открытых файлов/документов и список вьюшек, и каждая вьшка подписана на один или несколько файлов, чтобы улавливать изменения в них. Как файлов у вьюшки не остаётся, она закрывается.
И куда и как ты это будешь инкапсулировать? И почему списки вьюшек и документов не могут быть просто списками, ничего не знающими про вьюшки и документы?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Бинго! Вот он самый безопасный паттерн!
Только про паттерны не надо, пожалуйста.
>Кстати, про Вирта, как эта самая побитовая пересылка выглядит на паскале?
t1^ = t2^;
E>И, прости, а что происходит с оригиналом пересылки-то? Он разрушается или как? И кто зовёт деструктор того объекта, который затирают.
О господи! Еще раз — имеет место обмен.
PD>>Еще раз, внятно. FILE* file из текущего элемента обменивается с FILE* file из следующего элемента. Побитовый обмен. Никакие деструкторы тут не вызываются. После чего все идет как идет.
E>Про побитовый обмен -- это уже ново. До этого, у Вирта, например, речь шла о затирании одного другим вроде бы.
Тебе же очень нужно деструктор вызвать. Поэтому придется пойти на обмен. У Вирта только POD, так что достаточно переслать — удаление данных в ListElem у Вирта проблем не вызовет.
E>>>Правда копирование можно заменить на обмен. Но, к сожалению, даже менять можно не все объекты... PD>>Пример, пожалуйста. Наследование не предлагать — все элементы списка имеют всегда один и тот же тип. E>Почему это все элементы списка всегда имеют один и тот же тип? Скажем список контролов окна чем плох?
Тебе , видимо, надо азбучные истины объяснять.
Тип элемента списка ListElem. В него, конечно, может входить что угодно, но все элементы списка имеют один и тот же тип — ListElem. Список контролов окна сделать можно, если его поле данных — HWND, или HWND*, или CWnd* или даже CWnd, но тогда только CWnd, а не его наследники. Список из CWnd и CButton сделать нельзя.
E>Ну а пример простой очень. Объект, который где-то зарегистрирован вне списка. E>Ну, например, буфер для асинхронного получения данных из трубы. У меня список таких буферов. В деструкторах они себя разрегистрируют, и коннекшен закрывают. Ваши действия, уважаемый?
Опять деструкторы! При той операции, о которой говорилось, никаких лишних вызовов деструкторов нет. Деструктор вызывается, когда уничтожается объект, а не когда он пересылается в другой элемент списка.
struct ListElem
{
AnyType a;
ListElem* next;
};
ListElem* t1 = указатель на некий элемент в списке
ListElem* t2 = указатель на некий иной элемент в списке
swap(*t1, *t2 ;// побитовый обменdelete t1; // реально уничтожаем объект бывший t2
Где тут лишние деструкторы ?
With best regards
Pavel Dvorkin
Re[33]: Семантика значения есть далеко не у всех объектов ;)
E>Никогда слушателя сообщения в деструкторе не снимал?
Слушай, ты хоть определись наконец, о чем ты говоришь. Я за твоим полетом мыслей уже не в силах угнаться. То у тебя из внешнего мира какие-то ссылки на элементы списка. Теперь слушатели появились. Они в элементе списка или во внешнем мире ? Если в элементе списка, то их снятие ничем не отличается логически от удаления char*. Если же во внешнем мире, то объясни бога ради, как деструктор их разыскивает.
With best regards
Pavel Dvorkin
Re[34]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 18:28, Pavel Dvorkin wrote:
> Если же во внешнем мире, то объясни бога ради, как деструктор их разыскивает.
Я же всё показал. Даже код нарисовал.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[35]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Erop, Вы писали:
PD>>В общем случае — да. Но это уже не список объектов, а некая иная структура. Более того, ситуация, когда извне списка имеются указатели на его ListElem — мягко говоря, не очень хорошая. Тут и без всяких пересылок до неприятностей один шаг. В этом случае надо вообще-то заводить некий новый класс, инкапсулирующий в себе и List, и эти Subscriber'ы. А это уже иная песня.
E>Зачем? E>Вот представь себе, что есть список открытых файлов/документов и список вьюшек, и каждая вьшка подписана на один или несколько файлов, чтобы улавливать изменения в них. Как файлов у вьюшки не остаётся, она закрывается. E>И куда и как ты это будешь инкапсулировать? И почему списки вьюшек и документов не могут быть просто списками, ничего не знающими про вьюшки и документы?
Ничего не понимаю. Они, стало быть, должны быть просто списками, ничего не знающими про вьюшки и документы, но при этом хранить внутри указатели на элементы иного списка ?
On 19/08/10 18:24, Pavel Dvorkin wrote: > Тебе , видимо, надо азбучные истины объяснять. > Тип элемента списка ListElem. В него, конечно, может входить что угодно, > но все элементы списка имеют один и тот же тип — ListElem.
Это так называемый intrusive container. Знаешь что такое non-intrusive containers?
> AnyType a;
Не AnyType, а AnyBitwiseSwapableType!!!
> swap(*t1, *t2 ;// побитовый обмен
Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[35]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, ., Вы писали:
.>On 19/08/10 18:28, Pavel Dvorkin wrote:
>> Если же во внешнем мире, то объясни бога ради, как деструктор их разыскивает. .>Я же всё показал. Даже код нарисовал.
У тебя же внутри класса Set из этих ссылок. Или я что-то не так понял ?
With best regards
Pavel Dvorkin
Re[36]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 18:38, Pavel Dvorkin wrote:
>> > Если же во внешнем мире, то объясни бога ради, как деструктор их разыскивает. > .>Я же всё показал. Даже код нарисовал. > У тебя же внутри класса Set из этих ссылок. Или я что-то не так понял ?
Да. И что? В чём вопрос-то?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
>> swap(*t1, *t2 ;// побитовый обмен .>Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен?
Нет, конечно. Если внутри элемента есть указатели на его внутренние поля — конечно нет. И , разумееется, не должно быть внешних указателей, это мы уже обсуждали. Кажется, все, по крайней мере для 22:42 вечера (у меня уже голова пухнет от дискуссии с Егором . В остальных случаях я не вижу причин, почему по адресу P1 объект жить может, а по адресу P2 — нет. Может, есть что-то еще, сейчас что-то не соображу.
On 19/08/10 18:43, Pavel Dvorkin wrote:
> .>Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен? > Нет, конечно.
Вот и замечательно. А значит алгоритм меняющий связи в списке и алгоритм меняющий значения узлов в списке — разные алгоритмы, не эквивалентные. Нельзя просто так один заменить на другой.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
>> Тип элемента списка ListElem. В него, конечно, может входить что угодно, >> но все элементы списка имеют один и тот же тип — ListElem. .>Это так называемый intrusive container. Знаешь что такое non-intrusive containers?
The main difference between intrusive containers and non-intrusive containers is that in C++ non-intrusive containers store copies of values passed by the user
Все эти элементы в списке одного и того же типа — ListElem. Если можно иначе (кроме того что см. ниже) — объясни как.
Я про другое знаю — как в ядре ОС реализованы списки. Там, действительно, есть специальная структура с двумя указателями. к которой можно пришить любые данные. Строго говоря, совсем не обязательно, чтобы все ListElem были одного типа — достаточно, если из каждого ListElem можно добраться до следующего или предыдущего и определить объем данных. Но это уже не классический список.
Здравствуйте, ., Вы писали:
>> Нет, конечно. .>Вот и замечательно. А значит алгоритм меняющий связи в списке и алгоритм меняющий значения узлов в списке — разные алгоритмы, не эквивалентные. Нельзя просто так один заменить на другой.
Да бога ради. Ничего против не имею. Но речь-то шла не об этой экзотике, а об обычной ситуации. То. что алгоритмы неэквивалентны — формально согласен, но из этого для случаев без этой экзотики ничего не следует. А это экзотика, и мне она малоинтересна.
.>>Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен?
PD>Нет, конечно. Если внутри элемента есть указатели на его внутренние поля — конечно нет.
Кстати, по крайней мере в принципе эта ситуация легко разруливается. Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem, то эти указатели можно заменить на смещения относительно начала ListElem, после чего такие элементы можно свопировать.
Здравствуйте, Pavel Dvorkin, Вы писали:
>>Кстати, про Вирта, как эта самая побитовая пересылка выглядит на паскале? PD>t1^ = t2^;
А почему это побитовая?
Например, где гарантии пересылки прокладок между полями записи?
PD>О господи! Еще раз — имеет место обмен.
IMHO, не обмен, а обман
PD>Тебе же очень нужно деструктор вызвать. Поэтому придется пойти на обмен. У Вирта только POD,
Вроде бы у него там на паскале всё было. Так что термин POD там нерелевантен...
PD>так что достаточно переслать — удаление данных в ListElem у Вирта проблем не вызовет.
В постановке Вирта такого рода требования на порядок разрушения элементов списка невозможны.
Но всё равно вызможны требования со стороны аллокатора...
E>>Почему это все элементы списка всегда имеют один и тот же тип? Скажем список контролов окна чем плох?
PD>Тебе , видимо, надо азбучные истины объяснять. PD>Тип элемента списка ListElem. В него, конечно, может входить что угодно, но все элементы списка имеют один и тот же тип — ListElem. Список контролов окна сделать можно, если его поле данных — HWND, или HWND*, или CWnd* или даже CWnd, но тогда только CWnd, а не его наследники. Список из CWnd и CButton сделать нельзя.
Это почему это нельзя, когда все ими пользуются?
Правда изучи что такое интрузивный список. Не будешь таким смешным.
PD>Опять деструкторы! При той операции, о которой говорилось, никаких лишних вызовов деструкторов нет. Деструктор вызывается, когда уничтожается объект, а не когда он пересылается в другой элемент списка.
Ну как бы тебе пояснить, что НЕ ВСЕ ОБЪЕКТЫ МОЖНО ПЕРЕСЛАТЬ!!!
PD>Где тут лишние деструкторы ?
Тут хуже. Тут UB, так как побитовый обмен не POD данных
А потом некорректно отработают деструкторы.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[34]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если же во внешнем мире, то объясни бога ради, как деструктор их разыскивает.
Так же как и всегда. Рассылает им уведомление
Вот представь себе, что мы пишем какой-то редактор-визуализатор каких-то сложных данных. Данные хранятся в файлах/документах. Ну, например, это редактор/смотрелка описаний гаджетов.
Когда мы открываем документ, мы создаём ему view. При этом у документа может быть много view. Все view должны узнавать о том, что документ изменился, чтобы эти изменения отобразить. Поэтому документ будет рассылать уведомления о изменениях в себе, а view, когда они будут подключаться к документу, будут подписываться на эти уведомления.
Когда документ закрывают/разрушают, он всем ещё не отписавшимся слушателям шлёт уведомление, что типа пора отписываться, и проверяет в конце, что все отписались.
При этом некоторые view могут отображать сразу несколько документов, например (то есть они могут, например, показывать результаты сравнения содержимого документов).
Ну вот, в этом приложении, например, документы могут лежать в списке.
Это всё довольно обычная архитектура, если честно. Мне странно, что для тебя это всё новость.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[36]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ничего не понимаю. Они, стало быть, должны быть просто списками, ничего не знающими про вьюшки и документы, но при этом хранить внутри указатели на элементы иного списка ?
Вьюшки знают про документы. Документы про вьюшки, по крайней мере про какие-то интерфейсы к ним. А списки ни про что не знают. Они просто контейнеры, параметризованные типом элемента...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да бога ради. Ничего против не имею. Но речь-то шла не об этой экзотике, а об обычной ситуации. То. что алгоритмы неэквивалентны — формально согласен, но из этого для случаев без этой экзотики ничего не следует. А это экзотика, и мне она малоинтересна.
Эта "экзотика" присутствует в половине GUI...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[35]: Семантика значения есть далеко не у всех объектов ;)
On 19/08/10 22:45, Erop wrote: > Это всё довольно обычная архитектура, если честно.
Можешь не стараться описывать. Он называет это всё малоинтересной экзотикой.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Кстати, по крайней мере в принципе эта ситуация легко разруливается. Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem, то эти указатели можно заменить на смещения относительно начала ListElem, после чего такие элементы можно свопировать.
Даже это нелегко. Например, реализовать CAutoBuffer
таким образом, корректно и без потери эффективности не получится.
Я уже не говорю о том, что элементы списка могут быть довольно большими, и двигать их без особой причины может быть и накладно, а не только некорректно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А почему это побитовая? E>Например, где гарантии пересылки прокладок между полями записи?
А они мне на что ? Они unused.
PD>>О господи! Еще раз — имеет место обмен. E>IMHO, не обмен, а обман
Да уж, убийственный аргумент. Видимо, ничего больше не остается...
PD>>Тебе же очень нужно деструктор вызвать. Поэтому придется пойти на обмен. У Вирта только POD, E>Вроде бы у него там на паскале всё было. Так что термин POD там нерелевантен...
PD>>так что достаточно переслать — удаление данных в ListElem у Вирта проблем не вызовет. E>В постановке Вирта такого рода требования на порядок разрушения элементов списка невозможны. E>Но всё равно вызможны требования со стороны аллокатора...
E>>>Почему это все элементы списка всегда имеют один и тот же тип? Скажем список контролов окна чем плох?
PD>>Тебе , видимо, надо азбучные истины объяснять. PD>>Тип элемента списка ListElem. В него, конечно, может входить что угодно, но все элементы списка имеют один и тот же тип — ListElem. Список контролов окна сделать можно, если его поле данных — HWND, или HWND*, или CWnd* или даже CWnd, но тогда только CWnd, а не его наследники. Список из CWnd и CButton сделать нельзя. E>Это почему это нельзя, когда все ими пользуются?
E>Правда изучи что такое интрузивный список. Не будешь таким смешным.
On the other hand, an intrusive container does not store copies of passed objects, but it stores the objects themselves. The additional data needed to insert the object in the container must be provided by the object itself. For example, to insert MyClass in an intrusive container that implements a linked list, MyClass must contain the needed next and previous pointers:
class MyClass
{
MyClass *next;
MyClass *previous;
//Other members...
};
////////////////////////
Ну и при чем здесь это ? Речь шла о списке, имеющем list_node, и о возможности пересылки его полей.
А теперь будь добр привести код, в котором есть класс List, а в нем есть указатель на list_node start, но элемент по этому указателю показывает полем next не на list_node, а на что-то иное.
Код в студию, черт побери!
PD>>Опять деструкторы! При той операции, о которой говорилось, никаких лишних вызовов деструкторов нет. Деструктор вызывается, когда уничтожается объект, а не когда он пересылается в другой элемент списка.
E>Ну как бы тебе пояснить, что НЕ ВСЕ ОБЪЕКТЫ МОЖНО ПЕРЕСЛАТЬ!!!
PD>>Где тут лишние деструкторы ? E>Тут хуже. Тут UB, так как побитовый обмен не POD данных
Доказательства UB в студию. Не рассуждения, а доказательства. Пример, демонстрирующий UB.
Есть два блока памяти, одинакового размера и одинаковой структуры. Будь добр объяснить, почему нельзя один блок памяти переслать в другой при условии, конечно, что нет ссылок на этот блок или его части извне или изнутри него, кроме как ссылок управляющей структуры (списка в данном случае).
Кстати, познакомься на досуге со структурой PE-файлов и назначением секции .reloc. Полезное дело. Узнаешь, как блоки памяти не самой простой структуры перемещают в памяти.
E>А потом некорректно отработают деструкторы.
И это тоже докажи. Был некий объект по адресу P1. Если его деструктировать — все будет корректно. А потом его побитово пересадили по адресу P2, с соблюдением того, что выделено чуть выше. Вот и докажи, что теперь деструктор отработает некорректно.
With best regards
Pavel Dvorkin
Re[35]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Erop, Вы писали:
E>Вот представь себе, что мы пишем какой-то редактор-визуализатор каких-то сложных данных. Данные хранятся в файлах/документах. Ну, например, это редактор/смотрелка описаний гаджетов.
E>Когда мы открываем документ, мы создаём ему view. При этом у документа может быть много view. Все view должны узнавать о том, что документ изменился, чтобы эти изменения отобразить. Поэтому документ будет рассылать уведомления о изменениях в себе
Кому? View ? Бога ради. Или же list_node списка, где хранятся эти view ? Я имеено о последних говорил.
PD>Более того, ситуация, когда извне списка имеются указатели на его ListElem — мягко говоря, не очень хорошая.
E>Это всё довольно обычная архитектура, если честно. Мне странно, что для тебя это всё новость.
Это для меня не новость. Я вполне могу представить и более сложную структуру. Но вот сохранение ссылки на list_node, который вообще не данные, а промежуточная вспомогательная структура, ИМХО не есть хорошее дело, так как дает возможность вмешаться в структуру этого списка помимо его класса List. Что же касается структуры самого элемента данных — это иное дело, он может содержать, что требуется.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Кстати, по крайней мере в принципе эта ситуация легко разруливается. Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem, то эти указатели можно заменить на смещения относительно начала ListElem, после чего такие элементы можно свопировать.
E>Даже это нелегко. Например, реализовать CAutoBuffer
таким образом, корректно и без потери эффективности не получится.
Разбираться нет времени. Объясни в двух словах, почему не получится.
E>Я уже не говорю о том, что элементы списка могут быть довольно большими, и двигать их без особой причины может быть и накладно, а не только некорректно...
Здрасьте, я ваша тетя. Без тебя я бы об этом никак не догадался Вспомни, с чего все начиналось-то...
Кстати, если уж на то пошло, то я вообще не переношу в list_node какие бы то ни было данные размером > 4 байт. (исключение — double). Надо больше — делайте указатель на данные, а по нему хоть иерархию классов разводите. И с размерами проблем не будет, и хранить можно разные типы, и размер всегда 4 байта, и пересылать собственно данные не надо, достаточно переслать указатели. Вот и все.
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>Например, где гарантии пересылки прокладок между полями записи? PD>А они мне на что ? Они unused.
Дык это такое свойство операции, которую обычно понимают под "бинарная пересылка данных". Данные могут же ещё как-то использоваться, а не только из паскаля. Паскаль вообще на таком уровне работать не может. Вы же преподаватель, Павел! Следите за корректностью используемой терминологии. Вас же дети слушают и учатся.
E>>Но всё равно вызможны требования со стороны аллокатора... PD>
Зачем? Программирование, особенно на паскале, бустом никак не ограничивается...
И конструкция, когда у меня есть база, которая умеет сцепляться в списки, и у ней есть много разных наследников -- она совсем-совсем нередкая...
В том числе и при программировании на объектном паскале.
PD>Ну и при чем здесь это ? Речь шла о списке, имеющем list_node, и о возможности пересылки его полей.
Правда? Я вот читаю стартовое сообщение, там про односвязанный список, без уточнения его структуры:
На собеседовании задали задачку:
есть односвязанный список, необходимо его очистить эффективно начиная с конца без привлечения доплонительных внешних ресурсов (например дополнительной памяти).
PD>Код в студию, черт побери!
Ты правда не понимаешь?
struct CListNode {
CListNode* next;
// методы, для работы с узлом односвязанного списка
};
struct CMyAbstractControl : CListNode {
// Тут инфраструктура для работы с моими контролами, например контролами, не являющимися окнами.
};
class CMyListBox : public CMyAbstractControl {
// тут реализация
};
class CMyButton : public CMyAbstractControl {
// тут реализация
};
// и т. д.
PD>Доказательства UB в студию. Не рассуждения, а доказательства. Пример, демонстрирующий UB.
Доказательства простые -- стандарт С++. Бинарная пересылка данных не POD-объекта -- UB...
Пример -- пожалуйста пример. Представь себе, что мои контролы используют CListNode, как виртуальную базу
PD>Есть два блока памяти, одинакового размера и одинаковой структуры. Будь добр объяснить, почему нельзя один блок памяти переслать в другой при условии, конечно, что нет ссылок на этот блок или его части извне или изнутри него, кроме как ссылок управляющей структуры (списка в данном случае).
Потому, что у создателей языка могут быть свои соображения на этот счёт. По стандарту С++ нельзя. Увы.
В паскале вообще странно говорить о блоках памяти.
Кроме того, эти блоки ещё и большими могут быть и пересылать их туда-сюда без всякого повода просто накладно.
PD>Кстати, познакомься на досуге со структурой PE-файлов и назначением секции .reloc. Полезное дело. Узнаешь, как блоки памяти не самой простой структуры перемещают в памяти.
При чём тут это, и то, что не все объекты можно двигать бинарно?
PD>И это тоже докажи. Был некий объект по адресу P1. Если его деструктировать — все будет корректно. А потом его побитово пересадили по адресу P2, с соблюдением того, что выделено чуть выше. Вот и докажи, что теперь деструктор отработает некорректно.
Кури стандарт С++ Там явно сказано, что делать так, как хочешь ты -- UB.
Я понимаю, что ты хочешь сказать. Что в большинстве случаев всё будет хорошо. Я с этим согласен. Но "большинство случаев" и
"можно дать гарантии, что" -- это совсем разные предикаты
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[36]: Семантика значения есть далеко не у всех объектов ;)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Кому? View ? Бога ради. Или же list_node списка, где хранятся эти view ? Я имеено о последних говорил.
view, конечно, вернее тем, кто подпишется. Это не обязательно будут view. Но сами по себе view могут лежать в списке, который просто список и ничего про все эти уведомления не знает.
PD>Это для меня не новость. Я вполне могу представить и более сложную структуру. Но вот сохранение ссылки на list_node, который вообще не данные, а промежуточная вспомогательная структура, ИМХО не есть хорошее дело, так как дает возможность вмешаться в структуру этого списка помимо его класса List. Что же касается структуры самого элемента данных — это иное дело, он может содержать, что требуется.
Дык элемент данных -- это поле неинтрузивного списка. И указатель на это поле, таким образом, является указателем внутрь list_node...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Разбираться нет времени. Объясни в двух словах, почему не получится.
Потому, что содержит внутри себя буффер и указатель на буффер. Когда буффер внутри становится слишком мал, в указатель помещается указатель на аллокированный буфер достаточного размера...
Заменить указатель на смещение не получится потому, что GetPtr() должен работать без ветвления, а вычитать два совсем разных указателя в С++ нельзя.
PD>Кстати, если уж на то пошло, то я вообще не переношу в list_node какие бы то ни было данные размером > 4 байт. (исключение — double). Надо больше — делайте указатель на данные, а по нему хоть иерархию классов разводите. И с размерами проблем не будет, и хранить можно разные типы, и размер всегда 4 байта, и пересылать собственно данные не надо, достаточно переслать указатели. Вот и все.
"Вот и всё" -- это удвоение оверхеда на аллокацию на каждый элемент списка.
Ну и зачем нужна эта лишняя косвенность? Если уж разводить лишний указатель, то лучше список двусвязанным сделать и не страдать
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Мы всё ещё обсуждаем требования задачи и как их можно изменить/расширить/сузить и почему или вы уже першли к киданию какашками?
Здравствуйте, Erop, Вы писали:
E>Потому, что содержит внутри себя буффер и указатель на буффер. Когда буффер внутри становится слишком мал, в указатель помещается указатель на аллокированный буфер достаточного размера...
Все, хватит. Я же ясно писал — при отсутствии внешних ссылок и ссылок изнутри.
Я закончил, больше ответов не будет.
With best regards
Pavel Dvorkin
Re[41]: Сейчас же каникулы. Чего ты такой нервный?
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>Потому, что содержит внутри себя буффер и указатель на буффер. Когда буффер внутри становится слишком мал, в указатель помещается указатель на аллокированный буфер достаточного размера...
PD>Все, хватит. Я же ясно писал — при отсутствии внешних ссылок и ссылок изнутри.
Нет, ты писал не совсем так. Посмотри на что я ответил
Ты писал, что обычно можно заменить указатель внутрь объекта смещением. Я привёл тебе пример объекта, с которым так не получится.
Другой пример, когда у тебя внутри объекта есть какие-то библиотечные объекты. Например, контейнеры stl...
PD>Я закончил, больше ответов не будет.
Ну и слава Богу. Видимо ты узнал всё, что хотел
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Господи! Ну поднимись выше по ветке-то!
Сообщение с темой "CAutoBuffer" было ответом на сообщение с темой "P.S."
Вот его текст:
.>>Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен?
PD>Нет, конечно. Если внутри элемента есть указатели на его внутренние поля — конечно нет.
Кстати, по крайней мере в принципе эта ситуация легко разруливается. Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem, то эти указатели можно заменить на смещения относительно начала ListElem, после чего такие элементы можно свопировать.
И я показал тебе, что вполне бывают ситуации, когда эта байда не разруливается. Ни в принципе ни не в принципе, ни никак ещё...
Удачного вам семестра, Павел.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Господи! Ну поднимись выше по ветке-то! E>Сообщение с темой "CAutoBuffer" было ответом на сообщение с темой "P.S." E>Вот его текст:
.>>Ты хочешь сказать, что абсолютно любые 2 объекта можно обменять побитово? Ты точно уверен?
PD>>Нет, конечно. Если внутри элемента есть указатели на его внутренние поля — конечно нет.
E>Кстати, по крайней мере в принципе эта ситуация легко разруливается. Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem, то эти указатели можно заменить на смещения относительно начала ListElem, после чего такие элементы можно свопировать.
E>И я показал тебе, что вполне бывают ситуации, когда эта байда не разруливается. Ни в принципе ни не в принципе, ни никак ещё...
Уф! Пришлось все же разобраться с этим буфером.
Нет, ничего ты не показал. Повторяю сказанное ыыше : "Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem"
А у тебя ptr показывает то ли на что-то внутри структуры, то ли куда-то во внешний мир. О таких случаях я не говорил.
А вообще сказанное мной довольно-таки банально. Почитай в MSDN про based указатели. Там, правда, 64 бита вместо 32, но идея именно эта — база и смещение. Вот кусочек
For the Microsoft 32-bit and 64-bit C compilers, a based pointer is a 32-bit or 64-bit offset from a 32-bit or 64-bit pointer base. Based addressing is useful for exercising control over sections where objects are allocated, thereby decreasing the size of the executable file and increasing execution speed. In general, the form for specifying a based pointer is
type__based(base)declarator
The "based on pointer" variant of based addressing enables specification of a pointer as a base. The based pointer, then, is an offset into the memory section starting at the beginning of the pointer on which it is based. Pointers based on pointer addresses are the only form of the __based keyword valid in 32-bit and 64-bit compilations. In such compilations, they are 32-bit or 64-bit displacements from a 32-bit or 64-bit base.
One use for pointers based on pointers is for persistent identifiers that contain pointers. A linked list that consists of pointers based on a pointer can be saved to disk, then reloaded to another place in memory, with the pointers remaining valid.
Как тебе последняя фраза ?
E>Удачного вам семестра, Павел.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Уф! Пришлось все же разобраться с этим буфером. PD>Нет, ничего ты не показал. Повторяю сказанное ыыше : "Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem"
Ну если ты таки разобрался, то покажи, как положить в твой список CAutoBuffer, или, хотя бы std::string...
PD>One use for pointers based on pointers is for persistent identifiers that contain pointers. A linked list that consists of pointers based on a pointer can be saved to disk, then reloaded to another place in memory, with the pointers remaining valid. PD>Как тебе последняя фраза ?
Советую поэкспериментировать на сегментной памяти
Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
E>>Удачного вам семестра, Павел. PD>И вам успехов в освоении программирования!
Эх, Павел, Павел. Я-то желал вам удачи, как преподавателю. Но учиться тоже никогда не поздно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, McSeem2, Вы писали:
MS>Короче говоря, единственное нормальное решение задачи — инвертировать список, после чего пришибить от начала к концу. O(n) времени O(1) памяти. Любые другие решения являются больными. И вот закидайте меня помидорами — лучшего решения не существует в силу устройства этого вашего мира.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Уф! Пришлось все же разобраться с этим буфером. PD>>Нет, ничего ты не показал. Повторяю сказанное ыыше : "Если в ListElem есть поля, являющиеся указателями на что-то внутри ListElem" E>Ну если ты таки разобрался, то покажи, как положить в твой список CAutoBuffer, или, хотя бы std::string...
Прочти вышесказанное еще раз. Выделил специально.
PD>>One use for pointers based on pointers is for persistent identifiers that contain pointers. A linked list that consists of pointers based on a pointer can be saved to disk, then reloaded to another place in memory, with the pointers remaining valid. PD>>Как тебе последняя фраза ?
E>Советую поэкспериментировать на сегментной памяти E>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
Уф... Microsoft Specific для Win32/64 и сегментная память .
Структура, лежащая не в одном куске. offsetof плачет горючими слезами.
E>>>Удачного вам семестра, Павел. PD>>И вам успехов в освоении программирования! E>Эх, Павел, Павел. Я-то желал вам удачи, как преподавателю. Но учиться тоже никогда не поздно
Эх, Егор! Я тоже искренне желаю Вам удачи в освоении реального программирования, а не схоластического обсуждения стандарта языка. Могу посоветовать еще принять участие, скажем, в форуме по Win32 — там схоластику не очень любят, потому как решают реальные задачи
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>Ну если ты таки разобрался, то покажи, как положить в твой список CAutoBuffer, или, хотя бы std::string...
PD>Прочти вышесказанное еще раз. Выделил специально.
Лучше ты прочти выделенное
Или ты std::string тоже считаешь "неинтересным частным случаем"?
PD>Уф... Microsoft Specific для Win32/64 и сегментная память .
А! Так мы про списки исключительно под плоскую память тут обсуждаем? Ну ты бы предупредил, что ли
Вообще-то ситуация, когда в объекте есть указатель внутрь себя, она довольно частая именно в том случае, когда в объекте есть какой-то буфер и указатель внутрь этого буфера, а если буфера не хватила, то и куда-то вовне
PD>Структура, лежащая не в одном куске. offsetof плачет горючими слезами.
Почему обязательно именно struct? Данные могут иметь и более замысловатую структуру
Ещё раз предлагаю посмотреть на такой класс, как std::string, в некоторых популярных реализациях он работает с памятью так же, как и CAutoBuffer!
Просто академически можно рассуждать о таком списке и другом списке, но на практике списки, которым нужна возможность бинарно пересылать данные неприемлемы.
PD>Эх, Егор! Я тоже искренне желаю Вам удачи в освоении реального программирования, а не схоластического обсуждения стандарта языка. Могу посоветовать еще принять участие, скажем, в форуме по Win32 — там схоластику не очень любят, потому как решают реальные задачи
При чём тут схоластика? Я совершенно практически программирую, просто мой код портится потом под очень многие платформы. Например под многие телефоны и другие мобильные устройства...
Ну а писать список в расчёте на привязку именно к Win32 -- это, IMHO, безумие.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Qwazar, Вы писали:
Q>Слышал схожую задачу, с таким же некорректно сформулированным условием. Решение предполагалось такое как тут: http://www.rsdn.ru/forum/etude/3913898.aspx
Здравствуйте, Erop, Вы писали:
PD>>Прочти вышесказанное еще раз. Выделил специально. E>Лучше ты прочти выделенное E>Или ты std::string тоже считаешь "неинтересным частным случаем"?
Копаться в нем внутри нет времени, но скорее всего, там ничего особого нет.
Кстати, что касается CAutoBuffer. Если не секрет — какой глубокий смысл имеет char buffer[standardBufferSize]; и почему бы не сделать standardBufferSize параметром конструктора класса (с возможным значением по умолчанию) вместо того, чтобы параметром темплейта, и выделять под него память в конструкторе. По крайней мере можно будет управлять этим стандартным размером в рантайме, это раз. Но есть и второе. не мог бы ты объяснить, зачем ты транжиришь память на char buffer[standardBufferSize] в случае, когда его размера не хватило ? Завел новый буфер, а этот бы освободить, и дело с концом. Да нельзя.
PD>>Уф... Microsoft Specific для Win32/64 и сегментная память . E>А! Так мы про списки исключительно под плоскую память тут обсуждаем? Ну ты бы предупредил, что ли
. М-да...
E>Вообще-то ситуация, когда в объекте есть указатель внутрь себя, она довольно частая именно в том случае, когда в объекте есть какой-то буфер и указатель внутрь этого буфера, а если буфера не хватила, то и куда-то вовне
См. выше.
PD>>Структура, лежащая не в одном куске. offsetof плачет горючими слезами. E>Почему обязательно именно struct? Данные могут иметь и более замысловатую структуру
Это ты писал ?
E>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
E>При чём тут схоластика? Я совершенно практически программирую, просто мой код портится потом под очень многие платформы. Например под многие телефоны и другие мобильные устройства...
Успеха! И давай закончим дискуссию.
E>Ну а писать список в расчёте на привязку именно к Win32 -- это, IMHO, безумие.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Копаться в нем внутри нет времени, но скорее всего, там ничего особого нет.
Плохо. Я тебе на примере уже третий день объясняю, как оно работает, а у тебя всё равно "ничего особого нет"...
PD>Кстати, что касается CAutoBuffer. Если не секрет — какой глубокий смысл имеет char buffer[standardBufferSize];
Не секрет. Фишка в том, что аллокация -- это очень дорого. А буфер на стеке -- нет. Это одна из популярных техник, которая в С++ позволяет обойтись без alloca, без потери эффективности.
Сценарий использования такой. Пусть у тебя есть какая-то задача, требующая буфера, который обычно легко помещается на стеке, но иногда может быть сколь угодно большим. Например тебе надо обработать по одной строки в каком-нибудь текстовом файле. Ты заводишь CAutoBuffer с таким параметром, чтобы в обычном случае данные поместились в его внутренний буфер. И при использовании, говоришь ему какого размера нужен буфер и получаешь требуемое.
В результате, в обычных случаях, когда данных мало (строки в файле нормальной длины, не больше 4К, например) ты работаешь на стеке и не тратишь время на аллокации, а в редких случаях, когда данных много, работаешь на буфере, выделенном на куче. При этом, это всё происходит прозрачным для клиентского кода образом, за исключением того, что в первом режиме экземпляр CAutoBuffer содержит внутри себя указатель на себя же.
Так как большинство строк в программах короткие, то некоторые реализации STL используют аналогичную технику для std::string (в смысле для std::basic_string), то есть в экземпляре строки есть буффер, и если строка коротка, то используется он, а если нет, то используется буфер аллокированый на аллокаторе.
PD>>>Структура, лежащая не в одном куске. offsetof плачет горючими слезами. E>>Почему обязательно именно struct? Данные могут иметь и более замысловатую структуру
E>>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
Это просто омонимия. Имелась в виду структура данных.
E>>Ну а писать список в расчёте на привязку именно к Win32 -- это, IMHO, безумие. PD>Уф...
Думаешь не безумие?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Не секрет. Фишка в том, что аллокация -- это очень дорого. А буфер на стеке -- нет. Это одна из популярных техник, которая в С++ позволяет обойтись без alloca, без потери эффективности. E>Сценарий использования такой. Пусть у тебя есть какая-то задача, требующая буфера, который обычно легко помещается на стеке, но иногда может быть сколь угодно большим. Например тебе надо обработать по одной строки в каком-нибудь текстовом файле. Ты заводишь CAutoBuffer с таким параметром, чтобы в обычном случае данные поместились в его внутренний буфер. И при использовании, говоришь ему какого размера нужен буфер и получаешь требуемое. E>В результате, в обычных случаях, когда данных мало (строки в файле нормальной длины, не больше 4К, например) ты работаешь на стеке и не тратишь время на аллокации, а в редких случаях, когда данных много, работаешь на буфере, выделенном на куче. При этом, это всё происходит прозрачным для клиентского кода образом, за исключением того, что в первом режиме экземпляр CAutoBuffer содержит внутри себя указатель на себя же.
Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера.
Прозрачность для клиентского кода можно обеспечить, если завернуть это все в класс.
Да, это не переносимо. Но меня переносимость интересует мало, а в пределах Windows — это самое эффективное решение.
Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ?
PD>>>>Структура, лежащая не в одном куске. offsetof плачет горючими слезами. E>>>Почему обязательно именно struct? Данные могут иметь и более замысловатую структуру
E>>>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа... E>Это просто омонимия. Имелась в виду структура данных.
А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ?
E>>>Ну а писать список в расчёте на привязку именно к Win32 -- это, IMHO, безумие. PD>>Уф... E>Думаешь не безумие?
Здравствуйте, Erop, Вы писали:
E>Советую поэкспериментировать на сегментной памяти E>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
Ну давай.
struct ANYSTRUCT
{
// что хочешь
};
union ANYUNION
{
struct ANYSTRUCT as;
char arr[на sizeof(ANYSTRUCT)];
};
Ну и как ? Массив arr лежит непрерывно или нет ? Пройти его p++ можно или нет ? А если все же можно, значит, он лежит непрерывно. Но тогда и ANYSTRUCT лежит тоже непрерывно, иначе что это будет за union ?
И ни слова тут нет о том, как это реализовано. Хоть с плоской моделью, хоть с сегментной.
Другое дело, что непрерывность эта будет реализовываться довольно хитрым способом. В DOS придется в общем случае использовать huge-указатели, и непрерывность будет не в формате seg:ofs, а в формате физического адреса == 16*seg + ofs. В защищенном режиме 286 непрерывность будет обеспечена с помощью тех же huge-указателей, но механизм ее реализации будет намного сложнее (несколько записей в GTT/LDT, таких, что непрерывно меняется у них база).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера.
1) Представь себе я это всё знаю
2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу
3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле?
PD>Прозрачность для клиентского кода можно обеспечить, если завернуть это все в класс. PD>Да, это не переносимо. Но меня переносимость интересует мало, а в пределах Windows — это самое эффективное решение.
Ну тебя не интересует, а других интересует Я же тебе предлагал пояснить, что ты обсуждаешь списки заточенные только под винду?
PD>Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ?
Упражние можешь опубликовать, если хочешь
PD>А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ?
Ну так мы списки любых объектов обсуждали вроде?
PD>Думаю, что ты так ничего и не понял.
Ну так уж объясняете, товарищ преподаватель
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера. E>1) Представь себе я это всё знаю
Похоже. что не очень, см. ниже.
E>2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу
А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу.
E>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле?
Нет, по 4K. Не рутай коммитирование и резервирование. А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит.
PD>>Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ? E>Упражние можешь опубликовать, если хочешь
Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен.
PD>>А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ? E>Ну так мы списки любых объектов обсуждали вроде?
Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги.
PD>>Думаю, что ты так ничего и не понял. E>Ну так уж объясняете, товарищ преподаватель
Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу PD>А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу.
Зато будет нужен сам по себе VirtualAlloc, далеко не дешёвый, прямо скажем
E>>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле? PD>Нет, по 4K. Не рутай коммитирование и резервирование.
Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится.
E>>А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит.
CAutoBuffer -- это просто std::string очищенный от работы со строкой. Просто сам по себе механизм аллокации буфера. std::string можно написать поверх него, например.
Почему VirtualAlloc сюда никак не подходит?
Да потому, что он вообще не ту задачу решает. Нам (например в строке) надо не переаллокировать буфер уметь, а быстро его получать под нужный размер. Это основная операция.
Кроме того, VirtualAlloc вообще штука неудобная, потому, что не массштабируемая. Конечно, когда у тебя в программе есть какой-то *самый главный буффер", то можно зарезервировать под него 500 метров и коммитить понемножку. Но, если у тебя есть много буферов, в каких-то классах-данных, например, в строках или в небольших картинках или ещё в чём-то рассеянном по всей программе. И у тебя любой экземпляр может захотеть аллокировать большой буфер, но почти всем при этом хватает маленького, то подход с VirtualAlloc вообще неприменим. Просто потому, что адресного пространства не хватит на 32-битной ОС...
На всяк. случай напомню нить дискуссии.
Обсуждалось как наждо делать односвязанные списки. Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. Я возразил тебе, что есть много довольно классов, которые не позволяют себя просто так бинарно обменивать. Ты привёл довод, что эти классы являются неинтересными редкими частными случаями, а я привёл тебе пример такого класса, который к редким и неинтересным отнести сложно -- это std::string.
Вот давай сконцентрируемся на конкретном примере. Типа мы хотим разработать класс, который работает с каким-то данными переменной длины, с картинками или строками или ещё чем-то похожим. Для определённости пусть будут строки, но давай не углубляться собственно в строковую специфику и сконцентрируемся на работе с памятью. Вот мы хотим разработать такую строку, чтобы в случае коротких строк не тратить время на аллокацию буфера.
Я знаю два популярных эффективных подхода.
1) иметь пул коротких буферов, и брать строки оттуда. Эффективно, но не в многопоточном окружении, так как на работе с пулом нужна синхронизация.
Зато органично смотрится с COW, который тоже плохо совместим с многопоточнм окружением.
2) Иметь буфер в экземпляре, а если строка в такой буффер не помещается, то аллокировать буфер на аллокаторе. При копировании строки данные и буфер копируют. Имеем наклодные расходы на копирование строк, зато не имеем тормозов в многопоточном окружении. Во всяком случае на коротких строках, где удельный вес тормозов на одну букву получается особенно большим.
PD>Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен.
Ну я люблю решать интересные задачи. Как и все посетители этого раздела форума, я надеюсь.
PD>Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги.
Да не волнуйся. Я знаю и как структуры лежат и как аллокатры работают и много чего ещё. Я правда имел в виду структуру данных. Если ты знаешь какое-то другое слово, которое позволяло бы избежать такой путаницы, то сообщи его. В любом случае это всё не важно, в контексте обсуждения списков, так я назвал структуры данных или нет. Я-то не преподаватель и грамотно выражаться не обязан
PD>Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию
Какую такую амуницию? У меня тут жарко и я за компом в одних трусах
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу. E>Зато будет нужен сам по себе VirtualAlloc, далеко не дешёвый, прямо скажем
Далеко не такой дорогой, как ты думаешь. Проверял.
E>>>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле? PD>>Нет, по 4K. Не рутай коммитирование и резервирование. E>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится.
Нет.
lpAddress
The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
E>>>А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит. E>CAutoBuffer -- это просто std::string очищенный от работы со строкой. Просто сам по себе механизм аллокации буфера. std::string можно написать поверх него, например. E>Почему VirtualAlloc сюда никак не подходит? E>Да потому, что он вообще не ту задачу решает. Нам (например в строке) надо не переаллокировать буфер уметь, а быстро его получать под нужный размер. Это основная операция. E>Кроме того, VirtualAlloc вообще штука неудобная, потому, что не массштабируемая. Конечно, когда у тебя в программе есть какой-то *самый главный буффер", то можно зарезервировать под него 500 метров и коммитить понемножку. Но, если у тебя есть много буферов, в каких-то классах-данных, например, в строках или в небольших картинках или ещё в чём-то рассеянном по всей программе. И у тебя любой экземпляр может захотеть аллокировать большой буфер, но почти всем при этом хватает маленького, то подход с VirtualAlloc вообще неприменим. Просто потому, что адресного пространства не хватит на 32-битной ОС...
Все верно.
E>На всяк. случай напомню нить дискуссии. E>Обсуждалось как наждо делать односвязанные списки.
Не делать, а уничтожать с конца.
>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов.
Опять же не делать, а только уничтожать.
>Я возразил тебе, что есть много довольно классов, которые не позволяют себя просто так бинарно обменивать. Ты привёл довод, что эти классы являются неинтересными редкими частными случаями, а я привёл тебе пример такого класса, который к редким и неинтересным отнести сложно -- это std::string. E>Вот давай сконцентрируемся на конкретном примере. Типа мы хотим разработать класс, который работает с каким-то данными переменной длины, с картинками или строками или ещё чем-то похожим. Для определённости пусть будут строки, но давай не углубляться собственно в строковую специфику и сконцентрируемся на работе с памятью. Вот мы хотим разработать такую строку, чтобы в случае коротких строк не тратить время на аллокацию буфера. E>Я знаю два популярных эффективных подхода. E>1) иметь пул коротких буферов, и брать строки оттуда. Эффективно, но не в многопоточном окружении, так как на работе с пулом нужна синхронизация. E>Зато органично смотрится с COW, который тоже плохо совместим с многопоточнм окружением. E>2) Иметь буфер в экземпляре, а если строка в такой буффер не помещается, то аллокировать буфер на аллокаторе. При копировании строки данные и буфер копируют. Имеем наклодные расходы на копирование строк, зато не имеем тормозов в многопоточном окружении. Во всяком случае на коротких строках, где удельный вес тормозов на одну букву получается особенно большим.
Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
PD>>Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен. E>Ну я люблю решать интересные задачи. Как и все посетители этого раздела форума, я надеюсь.
Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни.
PD>>Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги. E>Да не волнуйся. Я знаю и как структуры лежат и как аллокатры работают и много чего ещё. Я правда имел в виду структуру данных. Если ты знаешь какое-то другое слово, которое позволяло бы избежать такой путаницы, то сообщи его.
Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ? Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше. Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна. Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить.
>В любом случае это всё не важно, в контексте обсуждения списков, так я назвал структуры данных или нет. Я-то не преподаватель и грамотно выражаться не обязан
Ну а я не обязан медитировать насчет твоих неграмотных выражений
PD>>Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию E>Какую такую амуницию? У меня тут жарко и я за компом в одних трусах
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Далеко не такой дорогой, как ты думаешь. Проверял.
Ну и во сколько раз дороже аллокировать 4К на VirtualAlloc, чем на стеке? На стеке это стоит одну несинхронизированную запись в память
E>>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится. PD>Нет.
Как проверял?
PD>lpAddress PD>The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
По факту было не так. Увы.
E>>Обсуждалось как наждо делать односвязанные списки. PD>Не делать, а уничтожать с конца.
Ну ты расширил толкование задачи, и предложил закольцовывать список. Я показал, тебе, что закольцовывать никогда не надо. Но дискуссия вышла за рамки именно уничтожения списков, так как возникли вопросы нужно ли хранить указатель на последний элемент, нужны ли барьеры и т. д... В зависимости от структуры (это не struct, а просто русское слово) списка и стратегии удаления элементов, разные подходы оказываются в разной степени применимы. Так что вопросы о том, как список устроен и как уничтожать его элементы, оказались тесно связаны.
>>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. PD>Опять же не делать, а только уничтожать.
Ну да, при некотором подходе к организации односвязанного списка, при уничтожении его элемента нужен бинарный обмен данных между двумя элементами...
PD>Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
Ну так, если ты правильно подберёшь константу, и тебе хватит стека, то хорошо работает всегда. Просто надо инструменты по назначению использовать.
Только это не моя идея. Я на её авторство нисколько не претендую. Я считаю, что это общее место, на самом деле
PD>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни.
Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же
PD>Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ?
Это всего лишь спор о словах. Просто ты меня неверно понял, а я не знаю, как в таком случае высказываться однозначно. Наверное надо писать полностью "структура данных", но длинно. IMHO, если собеседник пытается найти осмысленную трактовку тезисов, то есть работает в режиме конструктивного обсуждения, то такая омонимия не страшна. А если собеседник работает в режиме поиска неверных трактовок, то нафиг такие беседы
PD>Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше.
Да не бессмысленно. Вот картинка сделанная поверх CAutoBuffer'а -- пример структуры данных, которая может лежать непрерывно, а может и в нескольких кусках памяти, и может иметь указатели внутрь себя, а может и не иметь...
И вот именно такие картинки в список, требующий бинарного обмена данных, не положишь, однако...
PD>Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна.
Нет, не путал. Я про физические адреса вообще не думал, так как они из С++ недоступны.
Я тебе про другое говорил совсем. Если мы заменим указатель смещением, то мы не сможем сослаться на буфер аллокированный отдельно.
PD>Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить.
Телепалка у тебя не того, не прогрелась ещё наверное
PD>Ну а я не обязан медитировать насчет твоих неграмотных выражений
Ну так забудь уже о структурах тогда хоть прерывных, хоть нет
PD>М-да. Амуниция бывает не только в виде трусов
Доктор! Вы о чём собственно?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>Далеко не такой дорогой, как ты думаешь. Проверял. E>Ну и во сколько раз дороже аллокировать 4К на VirtualAlloc, чем на стеке? На стеке это стоит одну несинхронизированную запись в память
А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать.
E>>>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится. PD>>Нет. E>Как проверял?
Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV.
PD>>lpAddress PD>>The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
E>По факту было не так. Увы.
Обсуждать MSDN я не намерен.
E>>>Обсуждалось как наждо делать односвязанные списки. PD>>Не делать, а уничтожать с конца. E>Ну ты расширил толкование задачи, и предложил закольцовывать список.
Еще раз — прочти мое первое сообщение. Я только предложил (в шутку, кстати) алгоритм уничтожения с последнего элемента. Больше ничего. И позже я ничего о том, как эти списки создавать , не писал.
>Я показал, тебе, что закольцовывать никогда не надо. Но дискуссия вышла за рамки именно уничтожения списков, так как возникли вопросы нужно ли хранить указатель на последний элемент, нужны ли барьеры и т. д... В зависимости от структуры (это не struct, а просто русское слово) списка и стратегии удаления элементов, разные подходы оказываются в разной степени применимы. Так что вопросы о том, как список устроен и как уничтожать его элементы, оказались тесно связаны.
Ну и ладно. Примем применимость разных подходов (за что я всегда ратовал и, кстати, вовсе не объявлял тот прием, о котором писал, панацеей).
>>>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. PD>>Опять же не делать, а только уничтожать. E>Ну да, при некотором подходе к организации односвязанного списка, при уничтожении его элемента нужен бинарный обмен данных между двумя элементами...
И все же насчет делать — с моей стороны ни слова не было.
PD>>Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
E>Ну так, если ты правильно подберёшь константу, и тебе хватит стека, то хорошо работает всегда. Просто надо инструменты по назначению использовать.
Безусловно. Остается только хорошо подобрать константу
E>Только это не моя идея. Я на её авторство нисколько не претендую. Я считаю, что это общее место, на самом деле
Я тоже. Не хватало мне еще метод, описанный Виртом, себе приписывать
PD>>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни. E>Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же
Не пользуюсь никакими средствами. кроме головы.
PD>>Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ? E>Это всего лишь спор о словах. Просто ты меня неверно понял, а я не знаю, как в таком случае высказываться однозначно. Наверное надо писать полностью "структура данных", но длинно. IMHO, если собеседник пытается найти осмысленную трактовку тезисов, то есть работает в режиме конструктивного обсуждения, то такая омонимия не страшна. А если собеседник работает в режиме поиска неверных трактовок, то нафиг такие беседы
PD>>Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше. E>Да не бессмысленно. Вот картинка сделанная поверх CAutoBuffer'а -- пример структуры данных, которая может лежать непрерывно, а может и в нескольких кусках памяти, и может иметь указатели внутрь себя, а может и не иметь...
Продолжаешь выкручиваться.
E>И вот именно такие картинки в список, требующий бинарного обмена данных, не положишь, однако...
Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем.
PD>>Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна. E>Нет, не путал. Я про физические адреса вообще не думал, так как они из С++ недоступны.
М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так.
Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька.
E>Я тебе про другое говорил совсем. Если мы заменим указатель смещением, то мы не сможем сослаться на буфер аллокированный отдельно.
Не сможем. Я о пределах применимости метода Вирта писал с самого начала.
PD>>Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить. E>Телепалка у тебя не того, не прогрелась ещё наверное
Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов.
PD>>Ну а я не обязан медитировать насчет твоих неграмотных выражений E>Ну так забудь уже о структурах тогда хоть прерывных, хоть нет
Вообще-то лучше бы забыть о специалистах, которые путают режим ядра/супервизора с языком программирования. Да вот не дают они забыть. Ну а я по слабости своей никак эту дискуссию оборвать не решусь. Может, ты сам ее закончишь ? А то, боюсь, ты еще несколько открытий сделаешь
PD>>М-да. Амуниция бывает не только в виде трусов E>Доктор! Вы о чём собственно?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать.
Это другая задача.
PD>Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV.
На Win95 не получал. Там реально коммитили по 40К. Такое вот было экспериментальное наблюдение...
E>>По факту было не так. Увы. PD>Обсуждать MSDN я не намерен.
То, что коммитили больше, чем просишь, никак не противоречит MSDN.
PD>И все же насчет делать — с моей стороны ни слова не было.
Было. Например, ты писал, что всегда в своих списках ты всегда хранишь указатель на хвост...
PD>Безусловно. Остается только хорошо подобрать константу
Это не сложно. Прогони на типичных задачах программу и узнаешь необходимые размеры буфера...
PD>>>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни. E>>Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же PD>Не пользуюсь никакими средствами. кроме головы.
Ну тебе виднее, как оно надёжнее выходит
PD>Продолжаешь выкручиваться.
Или чинить телепалку.
PD>Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем.
Это ПЛОХОЕ решение!!! Если у тебя есть место под лишний указатель на ноду, то лучше сделать список двусвязанным, и ничего никогда не обменивать
Кроме того, что твой подход с указателем на данные гарантирует лишнюю косвенность при любом доступе (то есть тормоза забесплатно), то это ещё и увеличивает количество дорогих довольно аллокаций!
PD>М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так.
Блин! Мы с тобой обсуждаем списки или что?
PD>Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька.
Но и там всё равно работа с памятью идёт через логические адреса, а не через физические. Или ты знаешь реализацию С++ под ядро винды, которая умеет работать с указателями на физ. адрес?
PD>Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов.
Ну ты реализацию С++, которая с физическим адресами работает приведи, а там поговорим. Вполне так может быть, что я про такую просто не знаю. Ну значит узнаю
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать. E>Это другая задача.
См. выделенное.
PD>>Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV. E>На Win95 не получал. Там реально коммитили по 40К. Такое вот было экспериментальное наблюдение...
Закончим это обсуждение, все равно проверить негде. Но насчет 40 К — очень странно. Резервируем 64, коммитриуем 40, а потом как оставшиеся 24 коммитировать ? Дырки мне не нужны.
E>>>По факту было не так. Увы. PD>>Обсуждать MSDN я не намерен. E>То, что коммитили больше, чем просишь, никак не противоречит MSDN.
Учи матчасть.
lpAddress
the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
dwSize
The size of the region, in bytes. If the lpAddress parameter is NULL, this value is rounded up to the next page boundary. Otherwise, the allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+dwSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.
flAllocationType
PD>>И все же насчет делать — с моей стороны ни слова не было. E>Было. Например, ты писал, что всегда в своих списках ты всегда хранишь указатель на хвост...
PD>>Безусловно. Остается только хорошо подобрать константу E>Это не сложно. Прогони на типичных задачах программу и узнаешь необходимые размеры буфера...
М-да. Остается мне только найти типичные задачи
PD>>Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем. E>Это ПЛОХОЕ решение!!! Если у тебя есть место под лишний указатель на ноду, то лучше сделать список двусвязанным, и ничего никогда не обменивать E>Кроме того, что твой подход с указателем на данные гарантирует лишнюю косвенность при любом доступе (то есть тормоза забесплатно), то это ещё и увеличивает количество дорогих довольно аллокаций!
PD>>М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так. E>Блин! Мы с тобой обсуждаем списки или что?
Я в данный момент обсвждаю твое заявление насчет невозможности доступа к физической памяти из С++. Я тебя за язык не тянул, сам напросился.
PD>>Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька. E>Но и там всё равно работа с памятью идёт через логические адреса, а не через физические.
О господи! Ты же просто элементарных вещей не понимаешь!
>Или ты знаешь реализацию С++ под ядро винды, которая умеет работать с указателями на физ. адрес?
Уф. Придется ликбез устроить.
С++ не выделяет память. Ни в 0-м, ни в 3-м кольце. Не умеет он этого делать. Память выделяет некий системный вызов (вызов API), который ее запрашивает у системы. Максимум, что может делать RTL C++ — это запросить большой блок и устроить на нем свое подраспределение. Так работала куча в стародавние времена. Сейчас это передано системе (HeapAlloc, к вызову которой в конечном счете приводит new/malloc и т.д.).
Если системный вызов выделяет виртуальную память, то получим виртуальный адрес (можно и в 0, и в 3 кольце)
Если системный вызов выделяет физическую память, то получим физический адрес (можно только в 0 кольце)
Если когда-нибудь появится химическая память, то будет вызов для ее получения и получим химический адрес
PD>>Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов. E>Ну ты реализацию С++, которая с физическим адресами работает приведи, а там поговорим. Вполне так может быть, что я про такую просто не знаю. Ну значит узнаю
В огороде бузина. а в Киеве дядька. Ты этой фразой просто признался в том, что ты совершенно ничего не понимаешь в том, как устроено ядро.
Ладно, Егор. все, хватит. За тобой последнее слово, но вопросов не задавай — я не отвечу.
Мой тебе совет — проштудируй первую книгу Рихтера и книгу Соломона-Русстновича о внутреннем устройстве Windows. Пока что ты тут понимаешь не больше, чем я в программировании для iPad
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать. E>>Это другая задача. PD>См. выделенное.
Во-первых, CAutoBuffer, так же, как и alloca предназначен для таких сценариев, когда буфер не увеличивают, или увеличивают очень редко.
Во-вторых, тут получается хитрый размен.
Для маленьких буферов, которые бывают часто, имеем бесплатную аллокацию. Зато для больших имеем new.
При этом, большой буффер, кроме того, что выделять, надо потом ещё и обработать, по крайней мере инициализировать. По сравнению с инициализацией большого буфера new уже не выглядит таким дорогим. То есть, если мы будем измерять производительность системы в том, сколько байт в секунду она может обработать, то получим выигрыш. Кроме того, new не обязан быть дороже VirtualAlloc. Я знаю аллокаторы, которые быстрее.
Ну и, кроме всего прочего, VA не так экономно расходует адресное пространство.
PD>М-да. Остается мне только найти типичные задачи
Ну, обычно, когда ПО разрабатывают в утилитарных целях, типичные задачи знают. Это просто необходимо для оптимизации и настройки, так как часто оптимизация, после ловле багов, превращается в правильный выбор в тех или иных разменах, вроде память vs скорость. Ну, во всяком случае по моему опыту обычно бывает так.
PD>Я в данный момент обсуждаю твое заявление насчет невозможности доступа к физической памяти из С++. Я тебя за язык не тянул, сам напросился.
Ну какой смысл искать оговорки и неточности? Если ты пишешь обычную программу на С++ с рантаймом, стандартными потоками и прочей поддержкой стандарта, то ты никак не имеешь доступа к физ. адресам...
E>>Но и там всё равно работа с памятью идёт через логические адреса, а не через физические. PD>О господи! Ты же просто элементарных вещей не понимаешь! PD>На, посмотри PD>http://msdn.microsoft.com/en-us/library/ff554460(VS.85).aspx
MmAllocateContiguousMemory returns the base virtual address for the allocated memory. If the request cannot be satisfied, NULL is returned.
Обрати внимание, что работа со стороны программы всё равно идёт через virtual address
PD>С++ не выделяет память. Ни в 0-м, ни в 3-м кольце. Не умеет он этого делать. Память выделяет некий системный вызов (вызов API), который ее запрашивает у системы. Максимум, что может делать RTL C++ — это запросить большой блок и устроить на нем свое подраспределение. Так работала куча в стародавние времена. Сейчас это передано системе (HeapAlloc, к вызову которой в конечном счете приводит new/malloc и т.д.).
Ошибаешься. С точки зрения С++ программы, как раз С++ тебе память и выделяет. И как раз в этой вот выделенной рантаймом С++ памяти работает, например, std::string А то, как именно рантайм это всё делает -- это подробности данной реализации С++
PD>Если системный вызов выделяет виртуальную память, то получим виртуальный адрес (можно и в 0, и в 3 кольце) PD>Если системный вызов выделяет физическую память, то получим физический адрес (можно только в 0 кольце)
Это всего лишь функции. Функции могут быть любыми. Мы же говорили про списки там, и менеджеры кусков памяти, который работают с С++ указателями? Так указатели в винде всё равно будут работать через страничное преобразование, то есть, прямого доступа из самого языка к физическим адресам нет...
Или ты хочешь сказать, что под винду бывают драйвера, которые работают при отключенном страничном преобразовании? Я про такое не знаю, но я в этом не спец. Возможно и бывают, но обычные драйвера, что под NT, что под чикагу работают в логических адресах...
PD>В огороде бузина. а в Киеве дядька. Ты этой фразой просто признался в том, что ты совершенно ничего не понимаешь в том, как устроено ядро.
Во-первых, я на знание того, как устроено ядро не претендую. IMHO, досконально это могут знать только разработчики винды.
Во-вторых, к тому, как писать списки, это, IMHO, не имеет никакого о отношения.
Ну и в-третьих, если говорить в терминах С++, то доступ к памяти осуществляется через её модель. С++ предоставляет некую машину для работы с данными, которая реализует указатели и операции над ними. Вот если бы была реализация, где можно описать такой тип указателя, что операции по нему происходили бы по физическим адресам, минуя страничное преобразование и сегменты, то можно бы было говорить, что из С++ можно получить доступ к физическим адресам. А так, извини, но нет. Или ты в списке планируешь доступ к памяти через API осуществлять?
PD>Мой тебе совет — проштудируй первую книгу Рихтера и книгу Соломона-Русстновича о внутреннем устройстве Windows. Пока что ты тут понимаешь не больше, чем я в программировании для iPad
За совет спасибо. Первую я читал, а вторую не помню. Как она называется и зачем нужно её изучать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
MmAllocateContiguousMemory returns the base virtual address for the allocated memory. If the request cannot be satisfied, NULL is returned.
E>Обрати внимание, что работа со стороны программы всё равно идёт через virtual address
Нет, просто эта функция еще и маппирует в вирт. АП. Вот еще пример
MmGetPhysicalAddress
The MmGetPhysicalAddress routine returns the physical address corresponding to a valid nonpaged virtual address.
PHYSICAL_ADDRESS MmGetPhysicalAddress(
__in PVOID BaseAddress
);
Parameters
BaseAddress [in]
Pointer to the virtual address for which to return the physical address.
E>За совет спасибо. Первую я читал, а вторую не помню. Как она называется и зачем нужно её изучать?
Соломон, Руссинович. Внутреннее устройство Windows ... (было 2 издания, в одном вместо многоточия 2000, в другом 2003/XP). Изучать ее не нужно, а прочитать внимательно надо, чтобы понимать, кто за что отвечает и как там внутри все устроено.
Здравствуйте, Erop, Вы писали:
E>Ну и в-третьих, если говорить в терминах С++, то доступ к памяти осуществляется через её модель. С++ предоставляет некую машину для работы с данными, которая реализует указатели и операции над ними. Вот если бы была реализация, где можно описать такой тип указателя, что операции по нему происходили бы по физическим адресам, минуя страничное преобразование и сегменты, то можно бы было говорить, что из С++ можно получить доступ к физическим адресам. А так, извини, но нет. Или ты в списке планируешь доступ к памяти через API осуществлять?
Сделай милость, не говори о том. чего не знаешь. Эта тема весьма серьезна, и здесь многое чего есть. Посмотри хотя бы VirtualAlloc с флагом MEM_PHYSICAL, а потом AllocateUserPhysicalPages, MapUserPhysicalPages.
Это и выделение памяти, причем физической , и механизм доступа к ней (именно через АПИ), и даже доступ за пределами 4G в 32-битной системе, что уж с твоей точки зрения вообще невозможно. Возможно. Управление памятью — вопрос сложный, а ты в нем просто не разбираешься, ну и не надо высказываться.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>PHYSICAL_ADDRESS MmGetPhysicalAddress( PD> __in PVOID BaseAddress PD>); PD>Parameters PD>BaseAddress [in] PD>Pointer to the virtual address for which to return the physical address.
Ну и что? Как потом по PHYSICAL_ADDRESS получить или записать данные? С++ этого вроде не умеет.
PD>Соломон, Руссинович. Внутреннее устройство Windows ... (было 2 издания, в одном вместо многоточия 2000, в другом 2003/XP). Изучать ее не нужно, а прочитать внимательно надо, чтобы понимать, кто за что отвечает и как там внутри все устроено.
Спасибо. Марк Руссинович мужчина, похоже, интересный.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Сделай милость, не говори о том. чего не знаешь. Эта тема весьма серьезна, и здесь многое чего есть. Посмотри хотя бы VirtualAlloc с флагом MEM_PHYSICAL, а потом AllocateUserPhysicalPages, MapUserPhysicalPages.
PD>Это и выделение памяти, причем физической , и механизм доступа к ней (именно через АПИ), и даже доступ за пределами 4G в 32-битной системе, что уж с твоей точки зрения вообще невозможно. Возможно. Управление памятью — вопрос сложный, а ты в нем просто не разбираешься, ну и не надо высказываться.
Через API можно много куда доступ получить. Но при чём тут указатели и вообще модель памяти С++? С++ этого всего не умеет. Поэтому обсуждать все эти хитрости, при разработке списка на указателях смысла нет никакого
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Через API можно много куда доступ получить. Но при чём тут указатели и вообще модель памяти С++?
При том, что нет модели памяти С++. Есть модель памяти операционной системы, в которой работает программа, написанная хоть на С++, хоть на Дельфи, хоть на асме.
>С++ этого всего не умеет.
С++ вообще ничего не умеет. А программисты,пишущие на нем, могут сделать все, что позволяет сделать операционная система, в которой эта программа или модуль работает.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Егор,хватит. Пойми, наконец, что С++ тут вообще ни при чем. Если я на асме напишу этот вызов — что изменится ?
Да ничего не изменится. В том режиме проца, в котором работает винда адреса всё равно будут линейными, а не физическими. С++ тут при том, чот в принципе, можно представить себе реализацию, которая поддерживает особый тип указателей на физические адреса. И при их разыменовании генерит вызовы соответсвующего API. Но такой реализации С++, насколько я знаю, нет. Так что как ни крутись, но при работе по С++ным указателям ты будешь иметь дело с логическими адресами, и физические тут не при чём.
В общем, либо приыведи пример, когда собственно сам С++ код, а не вызовы стороннего по отношению к языку АPI, позволяет работать непосредственно с физ. адресами, либо признавай, что из С++ физ. адреса недоступны. API, которое позволяет работать с физ. адресами может быть доступно, а вот сама по себе работа, непочредственно через указатели -- нет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>При том, что нет модели памяти С++.
Это не так. Необходимые свойства модели памяти С++ ЯВНО описаны в стандерте языка. Почитай, тоже полезно
PD>Есть модель памяти операционной системы, в которой работает программа, написанная хоть на С++, хоть на Дельфи, хоть на асме. Это другой уровень абстракции. Модель памяти С++ реализуется поверх модели памяти ОС. При этом они не обязаны совпадать.
PD>С++ вообще ничего не умеет.
Неправда. С++ код умеет непосредственно работать с памятью, по логическим адресам. Умеет вызывать процедуры, тоде по логическим адресам.
PD>А программисты,пишущие на нем, могут сделать все, что позволяет сделать операционная система, в которой эта программа или модуль работает.
Это другой уровень абстракции, не имеющий непосредственного отношения к С++. С++ реализует свою модель памяти поверх модели памяти ОС. Например, можно реализовать С++, который будет на 32-й ОС работать с более длинными адресами. Просто это будет несколько неэффективно. Вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Егор,хватит. Пойми, наконец, что С++ тут вообще ни при чем. Если я на асме напишу этот вызов — что изменится ?
E>Да ничего не изменится. В том режиме проца, в котором работает винда адреса всё равно будут линейными, а не физическими. С++ тут при том, чот в принципе, можно представить себе реализацию, которая поддерживает особый тип указателей на физические адреса. И при их разыменовании генерит вызовы соответсвующего API. Но такой реализации С++, насколько я знаю, нет. Так что как ни крутись, но при работе по С++ным указателям ты будешь иметь дело с логическими адресами, и физические тут не при чём.
E>В общем, либо приыведи пример, когда собственно сам С++ код, а не вызовы стороннего по отношению к языку АPI, позволяет работать непосредственно с физ. адресами, либо признавай, что из С++ физ. адреса недоступны. API, которое позволяет работать с физ. адресами может быть доступно, а вот сама по себе работа, непочредственно через указатели -- нет
Егор, сил больше нет. Я тебе уже несколько раз объяснял, что С++ тут вообще ни при чем, но тебе хоть объясняй, хоть нет.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>При том, что нет модели памяти С++. E>Это не так. Необходимые свойства модели памяти С++ ЯВНО описаны в стандерте языка. Почитай, тоже полезно PD>>Есть модель памяти операционной системы, в которой работает программа, написанная хоть на С++, хоть на Дельфи, хоть на асме. Это другой уровень абстракции. Модель памяти С++ реализуется поверх модели памяти ОС. При этом они не обязаны совпадать. PD>>С++ вообще ничего не умеет. E>Неправда. С++ код умеет непосредственно работать с памятью, по логическим адресам. Умеет вызывать процедуры, тоде по логическим адресам. PD>>А программисты,пишущие на нем, могут сделать все, что позволяет сделать операционная система, в которой эта программа или модуль работает. E>Это другой уровень абстракции, не имеющий непосредственного отношения к С++. С++ реализует свою модель памяти поверх модели памяти ОС. Например, можно реализовать С++, который будет на 32-й ОС работать с более длинными адресами. Просто это будет несколько неэффективно. Вот.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Егор, сил больше нет. Я тебе уже несколько раз объяснял, что С++ тут вообще ни при чем, но тебе хоть объясняй, хоть нет.
Ты тут не в позу становись, а просто приведи премер кода, если такой умный.
Напомниаю тебе, что ты предположил, что я, обсуждая с тобой работу с С++ кода с памятью через указатели, и расположение в этой памяти структур данных перепутал физические и логические адреса. Я тебе сказал, что их невозможно перепутать, так как из С++ программы через указатели до физических адресов доступ получить нельзя. А ты тут уже третий день втираешь, что С++ не при чём. Возможно, это твоё "не при чём" обозначает тоже самое -- через указатели доступ получить нельзя. Но тогда бери свои слова про структуры и перепутанные адреса назад. Либо приводи пример кода, где по С++-указателям работают с физическими адресами. Либо признавай, что ты зашёл в своих измышлениях не туда.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Все, я больше не могу.
Ну раз у тебя больше нет аргументов, то признавай что был неправ и я логические и физические адреса не путал...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Егор, сил больше нет. Я тебе уже несколько раз объяснял, что С++ тут вообще ни при чем, но тебе хоть объясняй, хоть нет.
E>Ты тут не в позу становись, а просто приведи премер кода, если такой умный. E>Напомниаю тебе, что ты предположил, что я, обсуждая с тобой работу с С++ кода с памятью через указатели, и расположение в этой памяти структур данных перепутал физические и логические адреса. Я тебе сказал, что их невозможно перепутать, так как из С++ программы через указатели до физических адресов доступ получить нельзя. А ты тут уже третий день втираешь, что С++ не при чём. Возможно, это твоё "не при чём" обозначает тоже самое -- через указатели доступ получить нельзя. Но тогда бери свои слова про структуры и перепутанные адреса назад. Либо приводи пример кода, где по С++-указателям работают с физическими адресами. Либо признавай, что ты зашёл в своих измышлениях не туда.
Ты знаешь кого напоминаешь ? Школьника, которому Марья Ивановна рассказала, что при отрицательном дискриминанте квадратное уравнение корней не имеет. И в учебнике то же самое написано. И вот он теперь ходит и всем объясняет. что решений нет, потому что Марья Ивановна сказала и в учебнике написано. А когда ему начинаешь объяснять, что Марья Ивановнв еще не самый большой авторитет, и учебник тоже, и что есть еще целый мир, в котором это совсем не так — он опять повторяет про Марью Ивановну и учебник 8-го класса.
Никак ты понять не хочешь, что адресация — это свойство процессора и операционной системы, а не С++. Что эта адресация от языка не зависит. Что механизм трансляции адреса вообще от языка не зависит. Что доступ к физическим адресам возможен или невозможен, но это определяется ОС и процессором, а вовсе не языком. Что есть механизмы доступа к физической памяти напрямую (секция PhysicalMemory, пока ее не прикрыли, тот же ViryualAlloc/MEM_PHYSICAL, о котором я тебе говорил).
Все. Больше я ничего писать не буду. Можешь считать, что ты прав, можешь считать что хочешь, только отстань ради бога.
With best regards
Pavel Dvorkin
Re[67]: Павел! Вы знакомы с концепцией абстрактного мышления
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Никак ты понять не хочешь, что адресация — это свойство процессора и операционной системы, а не С++. Что эта адресация от языка не зависит. Что механизм трансляции адреса вообще от языка не зависит. Что доступ к физическим адресам возможен или невозможен, но это определяется ОС и процессором, а вовсе не языком. Что есть механизмы доступа к физической памяти напрямую (секция PhysicalMemory, пока ее не прикрыли, тот же ViryualAlloc/MEM_PHYSICAL, о котором я тебе говорил).
Это всё не совсем правда. Язык реалтзует СВОЮ модель памяти поверх средств ОС, которая, в свою очередь, реализует свою модель памяти поверх средств процессора и устройства управления памятью и прочего оборудования, котороен реализует всё это на уровне электрических сигналов на шинах и внутри микросхем, которые, в свою очередь, реализуют всё это поверх физических процессов в проводниках и полупроводниках и т. д.
Это просто несколько слоёв абстракции. Выделение слоёв абстракции и ведение рассуждений в рамках одного слоя, называется "абстрактным мышлением". Я думаю, что ты должен быть знаком с этой концепцией, хотя бы в общих чертах
Так как обсуждение устройства списков мы вели на языке/уровне объектов и модели памяти С/С++, то и абстракции надо использовать с того слоя, а не перескакивать на устройство процессора или квантовую физику...
PD>Все. Больше я ничего писать не буду. Можешь считать, что ты прав, можешь считать что хочешь, только отстань ради бога.
Ты ещё должен извиниться за то, что заявил, что я перепутал логические и физические адреса. В то, что я считаю физические адреса недоступными для реализаций С++ под винду ты наверное уже поверил?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[68]: После дискуссии с тобой я уже ни с чем не знаком. :-
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, SpaceConscience, Вы писали:
SC>Это ж надо какую-то невинную задачку умудриться превратить в срач! Неспроста возникло мнение, что RSDN предназначен в первую очередь для срачей.
Задача бессмысленная. Если бы в реальном проекте возникла необходимость очистить односвязный список с конца, следовало бы уволить того, по чьей вине такое возникло Я вообще поражаюсь тупости задач на собеседованиях.
У каждого объекта в программе есть какой-то идентификатор, по которому до объекта можно достучаться (иначе это уже утечка памяти). Для односвязного списка таким идентификатором является указатель на ПЕРВЫЙ элемент списка. Соответственно, не нужно извращаться, нужно взять этот указатель и, организовав обычный цикл по списку, его очистить.
Если для какой-то причины нужно очистить именно с конца — то рекурсия. И я бы еще внимательно посмотрел на архитектуру программы. Возможно, следует использовать двусвязный список или изменить логику хранения данных в списке, или что-то еще...