общий ресурс
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.12.19 07:23
Оценка:
привет!

есть класс, мембером которого является vector<type>.

этот класс может создавать обекты своего же типа, которые содержат только часть данных из "родительского":
struct myclass {
    using element_type = int;

    myclass at(size_t index) {
        element_type *p = ... // находим элемент по индексу
        size_t size = ...     // определяем размер

        return {p, size};
    }
private:
    myclasss(const element_type *p, size_t size)
    { m_ints.assign(p, size); }

    vector<element_type> m_ints;
};

(код сильно упрощен, и в векторе не int`ы)

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

как вариант: вектор можно хранить в shared_ptr, и тогда все дети могут ссылаться на него.
одно не нравится в этом варианте: нужны дополнительные мемберы, которые будут использоваться только детьми — значит код класса придется дополнить кучей условий проверки, дите или родитель %)

как быть?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 19.12.2019 7:27 niXman . Предыдущая версия .
Re: общий ресурс
От: Stanislav V. Zudin Россия  
Дата: 19.12.19 07:31
Оценка:
Здравствуйте, niXman, Вы писали:

X>есть класс, мембером которого является vector<type>.


X>этот класс может создавать обекты своего же типа, которые содержат только часть данных из "родительского":


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


X>одно не нравится в этом варианте: нужны дополнительные мемберы, которые будут использоваться только детьми — значит код класса придется дополнить кучей условий проверки, дите или родитель %)


X>как быть?


В зависимости от задачи. Может оформить аналогично std::string + std::string_view.
У себя в проекте я бы разделил твой класс на собственно "хранилище", в котором где лежит vector<type> и "итератор", тонкая прослойка, в которой лежит указатель на хранилище и индекс нужного элемента во внутреннем массиве. В неё же можно накидать доп. мемберы.
_____________________
С уважением,
Stanislav V. Zudin
Re[2]: общий ресурс
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.12.19 07:34
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

SVZ>В зависимости от задачи. Может оформить аналогично std::string + std::string_view.

получится то, чего не хочется — куча проверок на "дите"/"родитель"

SVZ>У себя в проекте я бы разделил твой класс на собственно "хранилище", в котором где лежит vector<type> и "итератор"

получится нелогично. потому что каждое "дите" может порождать других "детей" и является для них "родителем".
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 19.12.2019 7:36 niXman . Предыдущая версия .
Re: общий ресурс
От: Chorkov Россия  
Дата: 19.12.19 07:37
Оценка: 15 (1) +1
Здравствуйте, niXman, Вы писали:

X>привет!


X>есть класс, мембером которого является vector<type>.


X>этот класс может создавать обекты своего же типа, которые содержат только часть данных из "родительского":

X>
X>struct myclass {
X>    using element_type = int;

X>    myclass at(size_t index) {
X>        element_type *p = ... // находим элемент по индексу
X>        size_t size = ...     // определяем размер

X>        return {p, size};
X>    }
X>private:
X>    myclasss(const element_type *p, size_t size)
X>    { m_ints.assign(p, size); }

X>    vector<element_type> m_ints;
X>};
X>

X>(код сильно упрощен, и в векторе не int`ы)

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


X>как вариант: вектор можно хранить в shared_ptr, и тогда все дети могут ссылаться на него.

X>одно не нравится в этом варианте: нужны дополнительные мемберы, которые будут использоваться только детьми — значит код класса придется дополнить кучей условий проверки, дите или родитель %)

X>как быть?


В случае детей, если я правильно понял, все внуки (дети детей) одинаковые и метод at возвращает одно ии тоже (вычисляемое) значение.

Сделать две отдельных реализации myclass для родителя и для детей. (Шаблон проектирования p-impl.)
Re[2]: общий ресурс
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.12.19 07:45
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>В случае детей, если я правильно понял, все внуки (дети детей) одинаковые и метод at возвращает одно ии тоже (вычисляемое) значение.

тип — один, но внуки могут ссылаться только на часть данных от предка. (на самом деле это дерево, и дети ссылаются на поддеревья)

C>Сделать две отдельных реализации myclass для родителя и для детей. (Шаблон проектирования p-impl.)

да, вариант. в конструкторе проверять, соответствует ли переданный указатель нулевому элементу вектора? — если нет — значит дите...

какие еще варианты?

т.е. что-то типа этого:
struct myclass {
    using element_type = int;
    using storage_type = vector<element_type>;

    struct base {
        virtual shared_ptr<storage_type> get_storage() = 0; // используется для создания детей
    };
    struct parent: base {};
    struct child: base {};

    myclass(...) // конструктор родителя
        :pimpl{new parent(...)}
    {}

private:
    myclass(shared_ptr<storage_type> storage, const element_type *p, size_t size) // конструктор дитя
        :pimpl{new child(storage, p, size)}
    {}

private:
    base *pimpl;
};

(пока не компилил)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 19.12.2019 8:00 niXman . Предыдущая версия . Еще …
Отредактировано 19.12.2019 7:59 niXman . Предыдущая версия .
Отредактировано 19.12.2019 7:46 niXman . Предыдущая версия .
Re[3]: общий ресурс
От: Stanislav V. Zudin Россия  
Дата: 19.12.19 07:55
Оценка:
Здравствуйте, niXman, Вы писали:

SVZ>>В зависимости от задачи. Может оформить аналогично std::string + std::string_view.

X>получится то, чего не хочется — куча проверок на "дите"/"родитель"

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

SVZ>>У себя в проекте я бы разделил твой класс на собственно "хранилище", в котором где лежит vector<type> и "итератор"

X>получится нелогично. потому что каждое "дите" может порождать других "детей" и является для них "родителем".

когда твой объект становится "родителем", у него появляется свой собственный vector<type> или все они пользуются единым (назовём его "корневым")?

Например для работы с xml я использовал разделение на "Документ" и "узел".
Документ хранит все данные и обспечивает целостность.
А чтение, добавление, удаление узлов и атрибутов выполнялось через итераторы.

Как-то так.
    dom::Document document;
...
    dom::inode root = dom::root(document);
    
    for(dom::inode child = root.getChild(); !child.end(); ++child )
    {
        if ( xml::IsTag(child, NODE_TYPE) )
            doSomething(child);
    }
_____________________
С уважением,
Stanislav V. Zudin
Re[3]: общий ресурс
От: Chorkov Россия  
Дата: 19.12.19 08:25
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, Chorkov, Вы писали:


C>>В случае детей, если я правильно понял, все внуки (дети детей) одинаковые и метод at возвращает одно ии тоже (вычисляемое) значение.

X>тип — один, но внуки могут ссылаться только на часть данных от предка. (на самом деле это дерево, и дети ссылаются на поддеревья)

C>>Сделать две отдельных реализации myclass для родителя и для детей. (Шаблон проектирования p-impl.)

X>да, вариант. в конструкторе проверять, соответствует ли переданный указатель нулевому элементу вектора? — если нет — значит дите...

Нет, нет, нет.
Вариант p-impl был предложен, потому что меня смутила строчка
 { m_ints.assign(p, size); }

Я предположил что вектор заполняется одинаковыми заначениями, и хотел заменить хранение на вычисляемое поле.

X>какие еще варианты?


Если дело именно в хранении права владения то два варианта:
Либо перейти на умные указатели в самом дереве — тогда никаких проблем: время жизни именно нужнного поддерева проблевается автоматически.
Либо дети должны продлевать время жизни родетельского контейнера :

struct myclass {
    using element_type = int;
    using storage_type = vector<element_type>;

    myclass at(size_t index) {
        element_type *p = ... // находим элемент по индексу
        size_t size = ...     // определяем размер
        return {m_storage, p, size};
    }
private:
    myclasss(shared_ptr<storage_type> storage, const element_type *p, size_t size)
       : m_storage(storage_type) 
    { ... }


    shared_ptr<storage_type> m_storage;
};

p-impl ненужен.
Re: общий ресурс
От: Mr.Delphist  
Дата: 19.12.19 15:29
Оценка:
Здравствуйте, niXman, Вы писали:

X>есть класс, мембером которого является vector<type>.

X>...
X>этот класс может создавать обекты своего же типа, которые содержат только часть данных из "родительского":
X>...
X>проблема тут в том, что данные в "родительском" классе иммутабельны, но дети все равно вынуждены копировать их. от этого и хочется избавиться.

Я бы сказал, тут два подхода

1) данные хранятся где-то в стороне (тем более, если они иммуталбельны), а этот класс, родитель или дочерный, хранит лишь итераторы начала и конца данных
2) Перейти от хранения вектора к чему-то древообразному, тогда при порождении дочернего экземпляра в него можно вбрасывать лишь нужное поддерево (например, ссылкой или указателем)
Re: общий ресурс
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 19.12.19 17:15
Оценка:
Здравствуйте, niXman, Вы писали:

X>как быть?

Попробуй создать вектор через реаллокацию на памяти которую тебе дали. Если она линейна, то всё получится, главное не затереть. Другими словами, сделать плейсмент new по адресу который ты отдал и честно обращаться к той памяти. Возможно, надо написать свой аллокатор, отказаться от вектора или придумать свою абстракцию над этой конструкцией.
Sic luceat lux!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.