LINUX.ORG.RU

Списки как в ядре linux

 ,


1

2

Привет,

С++ для меня всегда был неким подобием черной магии, но грянул гром и теперь приходится его осваивать. Мне нужно включить класс в несколько дэков, при этом я могу выделить память только один раз для всего класса сразу. Я могу это сделать только явно и без последующих попыток перевыделения. То есть мне нужно то, что в ядре предоставляется связанными списками и несколькими вспомогательными макросами.

Вот функционал, аналогичный которому я ожидал бы увидеть: http://kernelnewbies.org/FAQ/LinkedLists

Как я понимаю std::deque мне не подходит так как: во-первых, std::deque, как я понимаю, сам инкапсулирует в себя нужный мне класс, а мне нужно наоборот; во-вторых, использует выделение памяти, при чем не совсем прозрачно.



Последнее исправление: CYB3R (всего исправлений: 2)
Ответ на: комментарий от Deleted

Нет. Я хочу выделить память для своей структуры, а в эту структуру должны быть инкапсулированы структуры, на предыдущий и следующий элемент в очереди. Примерно так:

struct my_struct
{
  struct list_head a;
  struct list_head b;
}

Когда буду итерироваться по элементам очереди, то я хотел бы получать указатель на класс, который инкапсулирует указатель на голову списка чем-то типа container_of (то чем занимается list_entry).

DesertFox
() автор топика
Ответ на: комментарий от quiet_readonly

std::deque<std::shared_ptr<> > если я правильно понял

Если я правильно понял то, что делает shared_ptr, так это то, что от обычного указателя он только автоматическим освобождением памяти отличается. Так что это не то что мне нужно.

copy+paste из ядра если нет

Ну это крайний вариант. Но не хочу выглядеть как программист из анекдота про фортранщика :)

DesertFox
() автор топика
Ответ на: комментарий от DesertFox

Нет.

Как ты себе это представляешь без дополнительного выделения памяти под новые элементы?

Deleted
()

при этом я могу выделить память только один раз для всего класса сразу.

Ты ведь говоришь о синглетоне?

O02eg ★★★★★
()
Ответ на: комментарий от DesertFox

Я хочу выделить память для своей структуры, а в эту структуру должны быть инкапсулированы структуры, на предыдущий и следующий элемент в очереди.

sys/queue.h же, там всё то же, что в линуксе, только чуток другими буквами. Если хочется солидно на плюсах, в бусте есть такие контейнеры. И да, обзывать объекты классами некультурно в приличном обществе ;)

const86 ★★★★★
()

насколько я тебя понял, то

class list_element
{
	public:
		list_element *next;
		list_element *prev;
};

class my_data: public list_element
{
	public:
		int data1;
		int data2;
		float data3;
		SuperPuperDataType data4;
};
конструктор можно написать так, что бы он prev и next модифицировал. ф-и добавления и удаления придётся самому написать.

nanoolinux ★★★★
()

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

shared_ptr, и не парь мозг.

nanoolinux ★★★★
()
Ответ на: комментарий от DesertFox

так это то, что от обычного указателя он только автоматическим освобождением памяти отличается. Так что это не то что мне нужно.

а что тебе нужно? сидеть потом с дебагером на перевес и искать к***** **** вызвала free два раза?

nanoolinux ★★★★
()
Ответ на: комментарий от Deleted

Я могу выделить дополнительную память под новые элементы, но дэк, этого сделать не может. То есть я выделяю память, а теперь хочу указать, чтобы в этой памяти располагалась структура со всеми заголовками очередей.

DesertFox
() автор топика

Ты много раз сказал, _что_ ты хочешь, но так и не сказал, _зачем_ тебе это нужно. Ты хочешь специфичную Си-фигню, которая нафиг не нужна в Си++ (если, конечно, ты не экономишь ресурсы до уровня подсчета байтов и циклов).

tailgunner ★★★★★
()
Ответ на: комментарий от DesertFox

нет, не нормально. есть наследование с человеческим синтаксисом. в С container_of и существует, потому-что хотим фич из спп, но не хотим спп. та же история с gtk с ихним gobject.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

есть наследование с человеческим синтаксисом. в С container_of и существует, потому-что хотим фич из спп

Это не тот случай. IIRC, ты не можешь указать в списке наследования один класс несколько раз.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

всё зависит от того, что именно нужно тс,

Ну, ядреные списки сделаны так, что элемент может находиться одновременно в нескольких списках _и_ занесение в эти списки делается без выделения памяти. Правда, решение очень в духе Си.

а он молчит как рыба.

...об лед

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ты хочешь специфичную Си-фигню

Интрузивные списки - специфичная си-фигня?

которая нафиг не нужна в Си++ (если, конечно, ты не экономишь ресурсы

Зачем тратить ресурсы, не получая ничего взамен?

unsigned ★★★★
()
Ответ на: комментарий от tailgunner

Мне нужно написать аллокатор, поэтому и нельзя выделять память. Это задание в универе. Честно говоря, подумав на свежую голову, мне кажется, что у меня нет необходимости включать объект в более чем один список. Но все равно интересно как такое можно в плюсах сделать.

DesertFox
() автор топика
Ответ на: комментарий от unsigned

Интрузивные списки - специфичная си-фигня?

Конкретная реализация интрузивных списков - специфичная Си-фигня.

Зачем тратить ресурсы, не получая ничего взамен?

«Время разработчика» - тоже ресурс, и его не следует тратить попусту.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от DesertFox

Но все равно интересно как такое можно в плюсах сделать.

Подозреваю, что придется парметриозвать шаблон «интрузивный_список» функцией «получить_линк» :)

tailgunner ★★★★★
()
Ответ на: комментарий от DesertFox

мне нужен Ъ-way для container_of в С++.

Если в одном контейнере все объекты одного класса, то шаблоны. Это не аналог container_of, но проблема отвалится сама собой.

const86 ★★★★★
()
Ответ на: комментарий от DesertFox

мне нужен Ъ-way для container_of в С++.

Есть подозрение, что не нужен.

O02eg ★★★★★
()

ну так учи Qt и забудь эти шаманские классы из STL (ненавижу STL, в других языках такого безобразия нет, по крайней мере не в такой степени)

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от tailgunner

Это не тот случай. IIRC, ты не можешь указать в списке наследования один класс несколько раз.

можно, если класс параметризован

в контексте топикстартера это может-быть что-то вроде Красивая реализация списков (комментарий)

class ByLoadOrder {}; 
class ByMemoryOrder {};
class ByInitializationOrder {};

struct SomeStruct;

struct SomeStruct:
    public IntrusiveList<SomeStruct, ByLoadOrder>,
    public IntrusiveList<SomeStruct, ByMemoryOrder>,
    public IntrusiveList<SomeStruct, ByInitializationOrder>
{
    PVOID              ModuleBase;         // module base address
    PVOID              ModuleEntry;        // module entry point
    ULONG              ModuleSize;         // module size (?)
    UNICODE_STRING     ModulePath;         // module full path
    UNICODE_STRING     ModuleName;         // module name
};

но возникает интересный вопрос — можно ли тут написать

struct SomeStruct:
    public IntrusiveList<SomeStruct, SomeStruct::*ModuleName>,
    public IntrusiveList<SomeStruct, SomeStruct::*ModuleSize>
{
...

подозреваю, что нельзя, и это обидно :-)

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)

Тред не читал. Интрузивные контейнеры тебе ннада. Тока от операций по выделению памяти никуда не децца. Спрятаны она за аллокатором или нет - дело десятое. Просто или ты отдаешь распределение памяти на откуп системе, или сам рулишь распределением памяти в своей песочнице.

slackwarrior ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

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

можно, если класс параметризован

Это разные классы. Хотя это может быть решением.

tailgunner ★★★★★
()
Ответ на: комментарий от DELIRIUM

Чтоб std::list подходил минимально, надо указатели хранить (адреса объектов) иначе копии будут.

slackwarrior ★★★★★
()
Ответ на: комментарий от www_linux_org_ru
struct SomeStruct:
    public IntrusiveList<SomeStruct, ByLoadOrder>,
    public IntrusiveList<SomeStruct, ByMemoryOrder>,
    public IntrusiveList<SomeStruct, ByInitializationOrder>

Ох, щи... Не проще какой-нибудь «variant» заюзать, если надо разные элементы в одном списке хранить или на край «абстр. интерфейс» элемента сделать? :) Интересно, преподы ТСа нарочно придумывают задания для решений, которыми никто не пользуется ИРЛ в сабжевом языке ? (то есть, можно, если хочется, но можно и не извращаться - юзать исконный и посконный С со списками как в ядре :))) Указатели на паблик мемберы-поля раскиданные ХЗ где, для доступа к которым все равно нужен адрес содержащего их экземпляра, - это вообще С++? :)

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

Не проще какой-нибудь «variant» заюзать, если надо разные элементы в одном списке хранить или на край «абстр. интерфейс» элемента сделать?

да ты можешь хоть на питоне писать — там вообще не надо заморачиваться какой-то статической типизацией

но если у тебя есть какое-то более простое решение со статической типизацией — приведи его (включая пример использования)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Причем тут статическая типизация? Или ты считаешь нормальным наследоваться от трех однотипных классов ради реализации сходного функционала?

slackwarrior ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

ненавижу STL

ок, тогда покажи Qt-замену для не-COW контейнеров и всех STL'ных алгоритмов, а также способ использования Qt-контейнеров с кастомным аллокатором и QHash со своей хэш-функцией для строк.

annulen ★★★★★
()
Ответ на: комментарий от tailgunner

Это разные классы. Хотя это может быть решением.

слова «разные классы» и «одинаковые классы» могут иметь разный смысл в зависимости от того, рассматриваем ли мы стандарт с++ или то, что человеку надо достичь; собственно это я и имел в виду в своем примере

никто не мешает к набору формально разных классов Clazz<T>, которые *реально* не зависят от Т, прикрутить общего предка IClazz и неявные преобразования из Clazz<U> в Clazz<V>

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от slackwarrior

Причем тут статическая типизация? Или ты считаешь нормальным наследоваться от трех однотипных классов ради реализации сходного функционала?

да, нормальным, поскольку нам нужны 3 инстанса одной и той же функциональности

хотя, впрочем, в с++0х можно было бы рассмотреть вариант variadic template вместо этого, но с точки зрения писанины это может быть и сложнее

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

слова «разные классы» и «одинаковые классы» могут иметь разный смысл

Во фразе «ты не можешь указать в списке наследования один класс несколько раз»- не могут.

Просто для протокола: Foo<T1> и Foo<T2> - это разные классы, порожденные одним шаблоном Foo.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

слова «разные классы» и «одинаковые классы» могут иметь разный смысл

Во фразе «ты не можешь указать в списке наследования один класс несколько раз»- не могут.

не просто могут, но и имеют разный смысл — более того, смысл того, что необходимо ТС, важнее

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Просто для протокола: Foo<T1> и Foo<T2> - это разные классы, порожденные одним шаблоном Foo.

с точки зрения пользователя этих классов это вовсе не обязательно так (т.е. эти классы для пользователя вовсе не обязательно различны); при этом проектировщик шаблона Foo может заставить компилятор уважать и учитывать точку зрения пользователя

хотя, конечно, кое-где поддержка этого может хромать

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от www_linux_org_ru

Просто для протокола: Foo<T1> и Foo<T2> - это разные классы, порожденные одним шаблоном Foo.

с точки зрения пользователя этих классов это вовсе не обязательно так

Неужели? Уже есть какая-то шаблонная магия, которая заставит компилироваться такое:

Foo<T1> *p = new Foo<T2>();

?

tailgunner ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Не обязательно пихать кучу одинакового всего N-раз в список наследования даже с точки зрения писанины, если ты не против всяких там неявных преобразований :) Можно шаблон твоего класса сделать достаточно умным для поддержки нескольких разных стратегий индексирования, ограничив эту разницу ими (не заморачиваясь наследованием от контейнера вообще - агрегация рулит - физически список все равно манипулирует не объектами, а адресами) - с какими там хошь конверсиями. Формально тебе нужны три политики жонглирования указателями, а инстансов может быть скока хошь и даже хранилище физических данных может быть одно :) Или тебе прям до зарезу нада полиморфный список? Выдыхай :)

slackwarrior ★★★★★
()
Ответ на: комментарий от tailgunner

с точки зрения пользователя этих классов это вовсе не обязательно так

Неужели? Уже есть какая-то шаблонная магия, которая заставит компилироваться такое: Foo<T1> *p = new Foo<T2>(); ?

я сказал «с точки зрения пользователя этих классов»

если это не понятно, приведу пример: в комнате есть 2 электророзетки в одинаковом состоянии, к которым подходят провода одинакового сечения из одного места; с точки зрения пользователя электрозеток, находящегося в центре комнты, эти розетки не отличаются, хотя ты, конечно, можешь определить, направо или налево идет провод к розетке, и пожаловаться на то, что нарушается феншуй :-)

чтобы твой вопрос стал хоть как-то обоснован, *ты* должен доказать, что как пользователю тебе потребуется Foo<T1> *p = new Foo<T2>(); для какой-то разумной цели

кстати, в случае IntrusiveList<S,T> это точно не потребуется, т.к. IntrusiveList это микс-ин и его вообще не стоит создавать отдельно от объекта-в-списке с помощью new IntrusiveList<S,T>(...)

а в общем случае это тоже скорее всего не потребуется, так как будет возможность юзать IFoo* p = ptr_to_foo_of_T2;

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от slackwarrior

Я ее не считаю просто ни единственно верной, ни удобной :) Особенно после оговорки про преобразования.

вообще не известно, считаешь ли там что-либо или просто поболтать вышел — пока что ты не обосновал ни одного своего... эээ... ну скажем так утверждения

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от slackwarrior

Или тебе прям до зарезу нада полиморфный список? Выдыхай :)

php ждет тебя, мой друг! там-то тебе точно не будут задавать вопросы «а полиморфный ли у тебя список? а не придется ли тут делать downcast-ы, верность которых компилятор не сможет проверить, и которые обломаются в рантайме?»

www_linux_org_ru ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.