Войти
ПрограммированиеФорумОбщее

[C++]<list> Полиморфность дохнет в stl контейнере. (2 стр)

Страницы: 1 2 3 4 Следующая »
#15
12:15, 7 окт. 2019

Товарищ аммиак объяснил всеправильно, но, возможно, недостаточно подробно.

Когда ты пишешь std::list , ты, как программист, говоришь, что в этом объекте будут храниться объекты размером sizeof(A). Объекты типа В в такое количество памяти могут прекрасно не влазить, поэтому никто их туда запихивать и не будет. Там будут храниться только объекты типа A.

Метод push_back никакой магии не делает. Он просто выделяет sizeof(A) памяти и вызывает там конструктор копирования с тем аргументом, который ты передал в качестве аргумента в метод push_back. В листе будет храниться эта копия типа А.

Когда ты пишешь std::list<std::unique_ptr>, ты говоришь, что в этом объекте будут храниться указатели на уже существующие объекты. Если ты передашь в push_back указатель на В, то для него (для указателя, а не для объекта) точно так же вызовется конструктор копирования, и информация о том, что это был указатель на В будет потеряна, храниться будет указатель на А. Но ссылка на виртуальную таблицу, которая хранится внутри самого объекта, останется, т.к. с самим объектом никто ничего не делал, поэтому полиморфизм будет работать.

Если нужно сохранять информацию о типах элементов контейнера, то нужно использовать другой тип контейнера (std::tuple), но это явно не то, что ты хочешь.

И все эти копирования не имеют под собой никакого заговора. Это ты сам пишешь такие конструкции. Если не хочешь копировать, то так и пиши, мол, не хочу копировать A(const A&) = delete; тогда компилятор тебе подскажет, что ты делаешь не так.


#16
12:18, 7 окт. 2019

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

#17
13:05, 7 окт. 2019

Клапауций
> а какого, спрашивается блина
Добро пожаловать с c++.

#18
13:29, 7 окт. 2019

Клапауций
как думаешь что будет если сделать так?

B b(42);
A a = b;
a.show();
#19
(Правка: 14:54) 13:49, 7 окт. 2019

#!
> возможно именно list тебе не нужен, пока std::deque тут уместнее
вольф мессинг отдыхает? здесь нет никакой прикладной задачи, чтобы делать такие выводы. :)

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

никаких new и delete в прикладном коде быть не должно!

например, что-то типа такого:

+ соорудил пока курил

Aroch
> как думаешь что будет если сделать так?
не думаю, делаю опыт.
намёк понял.
+1
спасибо.

+1 в мою сторону понимания, как же работает лист.

#20
(Правка: 14:14) 14:13, 7 окт. 2019

А я вот взял и завелосипедил интрузивный список, чтобы буст не тащить:

template < class T >
class List
{
protected:
  int size = 0;
  int swapCount = 0;
  T first = nullptr, last = nullptr;

public:

  List() {};
  virtual ~List() { clear(); };

  int getSize() { return size; };
  T &getFirst() { return first; };
  T &getLast() { return last; };
  int getSwapCount() { return swapCount; };

  void add( T item )
  {
    if ( last )
      last->next = item;
    item->prev = last;
    item->next = nullptr;
    last = item;
    if ( !first )
      first = item;
    size++;
  };

  void insert( T item, T before )
  {
    if ( !before )
      add( item );
    else
    {
      if ( before->prev )
      {
        item->prev = before->prev;
        item->prev->next = item;
      }
      else
      {
        first = item;
        item->prev = nullptr;
      };
      before->prev = item;
      item->next = before;
      size++;
    };
  };

  T remove( T item )
  {
    T nxt = item->next;
    T prv = item->prev;
    item->prev = nullptr;
    item->next = nullptr;
    if ( first == item )
    {
      first = nxt;
    };
    if ( last == item )
    {
      last = prv;
    }
    if ( prv )
    {
      prv->next = nxt;
    }
    if ( nxt )
    {
      nxt->prev = prv;
    }
    size--;
    return nxt;
  };

  void clear()
  {
    T cur = first;
    while ( cur )
    {
      T next = cur->next;
      cur->prev = nullptr;
      cur->next = nullptr;
      cur = next;
    };
    first = nullptr;
    last = nullptr;
    size = 0;
    swapCount = 0;
  };
};
Но не делал STL-совместимым, ибо не нужно было.
Для List<A*> нужно чтобы класс A (предок полиморфов) объявлял поля prev/next и делал шаблонный класс другом:
class A
{
 ...
  A *prev, *next;
  friend class List< A * > ;
};
То, что тип-указатель прописывается явно не баг, а фича - для поддержки умных указателей.
#21
14:29, 7 окт. 2019

=A=L=X=

ты нереально крут

#22
(Правка: 15:44) 14:50, 7 окт. 2019

=A=L=X=
> А я вот взял и завелосипедил интрузивный список
+100500 респекта

innuendo
> ты нереально крут
а innuendo cкорее всего пошутил :D

pahaa
+1
отдельное спасибо!

#23
16:10, 7 окт. 2019

=A=L=X=
> То, что тип-указатель прописывается явно не баг, а фича - для поддержки умных указателей.
На мой взгляд, это ты сделал зря, ибо это такой нереальный простор для выстрелов в ногу.
Лично мне сложно представить, когда там имеет смысл что-либо помимо обычных указателей.

А тех, кто принял неинтрузивные list, map и shared_ptr в std стоит уволить за профнепригодность.
#24
16:29, 7 окт. 2019

}:+()___ [Smile]
> А тех, кто принял неинтрузивные list, map и shared_ptr в std стоит уволить за
> профнепригодность.

facepalm | [C++]<list> Полиморфность дохнет в stl контейнере.
#25
17:09, 7 окт. 2019

innuendo
а что не так? тот же shared_ptr ещё с tr1 тащит за собой много всякого хлама, а наивные пользователи продолжают думать что там только указатель и счётчик
https://stackoverflow.com/questions/9200664/how-is-the-stdtr1shar… 01435#9201435

#26
17:17, 7 окт. 2019

#!
> а что не так?

не так это когда начинают изобретать велосипед там где не надо

#27
19:37, 7 окт. 2019

}:+()___ [Smile]
> На мой взгляд, это ты сделал зря, ибо это такой нереальный простор для
> выстрелов в ногу.
Если хочется умные указатели и интрузивный список одновременно, то иначе никак - надо смотреть чтобы выстрелить не получалось.
Ну а так как список по сути несложная структура где удаление из списка как раз отстыковывает указатели, то глюков с зацикливанием ссылок как раз быть не должно.

#28
22:11, 7 окт. 2019

=A=L=X=
> глюков с зацикливанием ссылок как раз быть не должно
Это пока у тебя только удаление, а вот если делать разные алгоритмы, хоть ту же сортировку, сразу возникнет геморрой на ровном месте. Вообще, что список, что умный указатель, — это, по сути, контейнеры, и заворачивать один в другой — это переголова.

Кстати, двусвязный список у тебя неоптимальный, обычно проще сделать сам список одной из нод и выкинуть специальный код обработки концов списка. Вот мой велосипед из относительно свежего проекта:

+ Код

#29
22:59, 7 окт. 2019

https://gpfault.net/posts/intrusive-lists-doom3.txt.html

Страницы: 1 2 3 4 Следующая »
ПрограммированиеФорумОбщее