LINUX.ORG.RU

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

 ,


1

2

Привет,

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

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

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



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

Пример про розетки канает не больше за обоснование :) Покуда ты не придумал волшебный переходник с агрегатов типа стир. машины на обычные розетки, от которых у юзера твоего решения не сгорят к х*м и правые и левые провода :)

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

Покуда ты не придумал волшебный переходник

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

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

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

А ты не груби :)

пока что даже и не начинал; жду код, или обоснования

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

А ты уже запостил рабочий-то? Или твои... эээ... высказывания обосновал «не обязанностью». Так это покуда тебя не обязали (материально) - по факту выгорания проводки у пользователя :) Пользователь вообще не обязан интересоваться деталями твоей реализации. *Ты* по ТЗ кровь из носу обеспечиваешь и интерфейс, и поведение, и надежность нужные пользователю, а не наоборот. Нравится тебе микс-ин - а пользователю до фонаря :) Устанавливаешь стир. машины - устанавливаешь специальную розетку и только в нее можно втыкать стир. машину :)

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

Или твой пример с розетками насквозь искусственный, подгоняющий реальность под твои ожидания, без достаточных обоснований. :) Удобно ты устроился.

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

А ты уже запостил рабочий-то?

бугага!!!

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

понятно, что он именно рабочий, и проясняет *идею*, а не является готовой библиотекой типа boost::intrusive::list

кстати, я *принимаю* критические высказывания по этому коду, при условии, что ты к нему отнесешься именно как демонстрации идеи

при этом, мне интересно, как в аггрегировании (ты его предлагал)

struct MyStruct {
   int x;
   LinkedList<MyStruct> list;
   ...

ты избежишь бойлерплейта в виде необходимости указывать еще и list(this) в конструкторе или необходимости ставить list первым членом

а я — избежал

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

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

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

вот только видимо так можно/нужно будет делать все же не в любом контексте

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

Я агрегирую не списки, а индексы. Естественно, это просто иллюстрация идеи, а не готовая библиотека (накидал за 15 минут) :) Индексов разных и одинаковых типов может быть сколько угодно, лежать они могут в разных списках. Память на индексируемые объекты расходуется один раз, там где они создаются. Полиси индексирования и хранения тоже можно делать разные (не обязательно «хранить» потомков одного класса, потому что в списке только индекс, индексаторы не тупо копипастить, а обобщить - и отломить ненужную полиси, почти не трогая остального, или добавить нужную).

//intrusive_polisy_based.h
#pragma once
#include <iostream>
#include <stdlib.h>
namespace Intrusive
{
  namespace Containers
  {
     template <class ElemType>
     struct BaseElement
     {

	ElemType* prev;
	ElemType* next;
	
     };
    
     template<typename T>
     struct ElemTraits
     {
       struct IndexTypeTrait {};
       struct TransformTrait {};
     };
     
     template<typename T, class Indexator = typename ElemTraits<T>::IndexTypeTrait, 
			  class Transformator = typename ElemTraits<T>::TransformTrait >
     class IntrusiveList: public Indexator, public Transformator
     {
     private:
       typedef typename ElemTraits<T>::ElemType Element;
       typedef typename ElemTraits<T>::Contained Contained;
       typedef typename ElemTraits<T>::IndexType IndexType;
       
     public:
       IntrusiveList()
       : Indexator(),
         Transformator(),
         first_(0),
         last_(0)
       {
	 
       }
       
       ~IntrusiveList()
       {}
       
       void push_back(Element* e)
       {
	 if (!last_)
	 {
	    last_ = e;
	    first_ = e;
	    e->value = 0;
	    e->prev = 0;
	    e->next = 0;
	    return;
	 }
	  last_->next = e;
	  e->value = last_->value;
	  ++e->value; // this action also may be in indexator polisy
	  e->prev = last_;
	  e->next = 0;
	  last_ = e;
      }
      
       void push_front(Element* e)
       {
	 if (!first_)
	 {
	    last_ = e;
	    first_ = e;
	    e->value = 0;
	    e->prev = 0;
	    e->next = 0;
	    return;
	 }
	  first_->prev = e;
	  e->value = first_->value;
	  ++e->value; // this action also may be in indexator polisy
	  e->prev = 0;
	  e->next = first_;
	  first_ = e;
       }      
       
       
       
       int size()
       {
	 int i(0);
	 for(Element* idx = first_; idx!=0; idx=idx->next, ++i) 
	 {
	   std::cout << "seek element " << idx->value << std::endl; 
	 }
	 return i;
       }
       
       bool empty()
       {
	 return first_;
       }
       
       Contained front()
       {
	  return this->Transformator::transform(*first_); 
       }
       Contained back()
       {
	  return this->Transformator::transform(*last_); 
       }
       
	Contained* get_by_index(IndexType idx)
	{
	   
	   return this->Transformator::transform_ptr(this->Indexator::get_by_value(first_, idx));
	}

     private:
       Element* first_;
       Element* last_;
       
     };
  }
}


//int_element.h

#pragma once
#include "intrusive_policy_based.h"
namespace Intrusive
{
  

  namespace Elements
  {
     
     template<typename Contained=int> 
     struct IntIndex: public Containers::BaseElement<IntIndex<Contained> >
     {
       IntIndex()
       {}
       IntIndex(const IntIndex& ii)
       : value(ii.value)
       , c(ii.c)
       {
	 
      }
       int value;
       Contained* c;
     };
     
     
     template<typename Contained=long> 
     struct LongIndex: public Containers::BaseElement<LongIndex<Contained> >
     {
       LongIndex()
       {}
       LongIndex(const LongIndex& ii)
       : value(ii.value)
       , c(ii.c)
       {
	 
      }
       long value;
       Contained* c;
     };     
     
    
  }
    
}
#include <iostream>

#include "intrusive_policy_based.h"
#include "int_element.h"
using namespace Intrusive::Containers;
using namespace Intrusive::Elements;



 struct Felide
 {
 Felide()
 : intId()
 , longId()
 {
    intId.c = this;
    longId.c = this;
 }  
 
 virtual ~Felide() {}  
 virtual void meow() = 0;
 
  IntIndex<Felide> intId;
  LongIndex<Felide> longId;
   
 };

 
 struct TomCat: public Felide
 {
   TomCat() {}
   virtual ~TomCat() {}
    void meow() { std::cout << "Meow!" << std::endl; }
 };

 struct Tiger: public Felide
 {
   Tiger() {}
   virtual ~Tiger() {}
   void meow() { std::cout << "AGRRRRRR!" << std::endl; }  
 };
 
 struct Lynx: public Felide
 {
   Lynx() {}
   virtual ~Lynx() {}
   void meow() { std::cout << "PPHHHHH!!" << std::endl;} 
   
   
 };
 
 

     struct IntIndexator
     {
        IntIndex<Felide>* get_by_value(IntIndex<Felide>* first, int value)
	{
	   
	  IntIndex<Felide>* ret = NULL;
	  for (IntIndex<Felide>* i=first; i!=NULL; i=i->next)
	  {
	    
	    if (i->value == value) 
	    {
	      ret = i;
	      break;
	    }
	  }
	  return ret;
	}
     };
     
     struct LongIndexator
     {
        LongIndex<Felide>* get_by_value(LongIndex<Felide>* first, long value)
	{
	  LongIndex<Felide>* ret = NULL;
	  for (LongIndex<Felide>* i=first; i!=NULL; i=i->next)
	  {
	    if (i->value == value) 
	    {
	      ret = i;
	      break;
	    }
	  }
	  return ret;
	}
     };     
     

     struct IntTransformator
     {
       Felide& transform(IntIndex<Felide>* ptr)
       {
	  return *(ptr->c);
       }
       Felide* transform_ptr(IntIndex<Felide>* ptr)
       {
	  return ptr->c;
       }
       
    }; 
     
     struct LongTransformator
     {
       Felide& transform(LongIndex<Felide>* ptr)
       {
	  return *(ptr->c);
       }
       Felide* transform_ptr(LongIndex<Felide>* ptr)
       {
	  return ptr->c;
       }
       
    };     
     

namespace Intrusive
{
  namespace Containers
{
    template<>
    struct ElemTraits<IntIndex<Felide> >
    {
      typedef Felide Contained;
      typedef IntIndex<Felide> ElemType;
      typedef IntIndexator IndexTypeTrait;
      typedef IntTransformator TransformTrait;
      typedef int IndexType;
    }; 
    
    template<>
    struct ElemTraits<LongIndex<Felide> >
    {
      typedef Felide Contained;
      typedef LongIndex<Felide> ElemType;
      typedef LongIndexator IndexTypeTrait;
      typedef LongTransformator TransformTrait;
      typedef long IndexType;
    };     
}
}
 
 typedef IntrusiveList<IntIndex<Felide> > CatsList;
typedef IntrusiveList<LongIndex<Felide> > LongCatsList;

int main(int argc, char **argv)
{
  CatsList cl;
  LongCatsList cl2;
  
  TomCat tc;
  Tiger t;
  Lynx l;
  
  Lynx l1;
  Lynx l2;
  Lynx l3;
  Lynx l4;
  
//those push should be more complicated for index-safety of similar types like int and long 
  cl.push_back(&tc.intId);
  cl.push_back(&t.intId);
  cl.push_back(&l.intId);
  
  cl2.push_back(&l.longId);
  cl2.push_back(&l1.longId);
  cl2.push_back(&l2.longId);
  cl2.push_back(&l3.longId);
  cl2.push_back(&l4.longId);
  
  
  std::cout << "list 1 size is " << cl.size() << std::endl;
  std::cout << "list 2 size is " << cl2.size() << std::endl;
  
  int cl2Size = cl2.size();
  for (int i = 0; i <= cl2Size-1; ++i)
  {
    Felide* f = cl2.get_by_index(i);
    f->meow();
  }
  
  int clSize = cl.size();
  for (int i = 0; i <= clSize-1; ++i)
  {
    Felide* f = cl.get_by_index(i);
    f->meow();
  }  
   
  return 0;
}
bash-4.2$ g++ -o intr main.cpp 
bash-4.2$ ./intr
seek element 0
seek element 1
seek element 2
list 1 size is 3
seek element 0
seek element 1
seek element 2
seek element 3
seek element 4
list 2 size is 5
seek element 0
seek element 1
seek element 2
seek element 3
seek element 4
PPHHHHH!!
PPHHHHH!!
PPHHHHH!!
PPHHHHH!!
PPHHHHH!!
seek element 0
seek element 1
seek element 2
Meow!
AGRRRRRR!
PPHHHHH!!
slackwarrior ★★★★★
()
template <typename T, template<typename ELEM, typename ALLOC = std::allocator<ELEM> > class CONTAINER = std::deque>
class UglyClass
{
.....
};
Boy_from_Jungle ★★★★
()
Ответ на: комментарий от slackwarrior
struct Felide
{
   Felide()
   : intId() // бойлерплейт
   , longId() // бойлерплейт
   {
      intId.c = this; // бойлерплейт
      longId.c = this; // бойлерплейт
   }  
   ...

ну вот, ты использовал агрегацию вместо наследования, и вынужден писать этот бойлерплейт; у меня же было достаточно объявить

struct Felide: 
   public IntrusiveList<Felide, че-то-там>,
   public IntrusiveList<Felide, че-то-другое>
и все

кроме того, у тебя он получился почему-то в ухудшенном варианте, и создатель класса Felide должен *знать* и инициализировать отнюдь не очевидное поле ".с" вместо простого вызова конструктора навроде

Felide(): intId(this), longId(this)

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

еще вижу кучу typedef-ов; для показа идеи можно их было и не писать (хотя на продакшене они конечно нужны) — они приводят меня к мысли, что такой класс стоило бы снабдить итератором в стиле STL, что видимо я и сделаю для своего кода

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

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

Копипаст, как ты говоришь, иллюстрация идеи, как и отсутствие итераторов :) Там можно трансформатор шаблонный вставить или не вставлять никакой :) Аналог на Ц я и не думал писать - для этого есть Ц.

slackwarrior ★★★★★
()
Ответ на: комментарий от www_linux_org_ru
struct Felide: 
   public IntrusiveList<Felide, че-то-там>,
   public IntrusiveList<Felide, че-то-другое>

У меня лист по сути написан один :) У тебя - дубль в списке наследования. Что лучше? :)

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

Ггг. Меня еще «цыганом» ругали понаехалы с ДЦ :) А я с покоса - мне все по 5.1.

Ну и http://en.wiktionary.org/wiki/felide :) Че-там теперь с твоим фейспалмом?

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

У меня лист по сути написан один :) У тебя - дубль в списке наследования. Что лучше? :)

это хороший неочевидный вопрос, который следует обдумать

кстати, я постил вариант без дублей Красивая реализация списков (комментарий)

одно «но»: афайк в с++ в компайл-тайме нельзя проитерироваться по элементам enum-a, поэтому либо придется указывать количество списков явно, либо еще как-то модернизировать код (но это легко)

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

Ну и http://en.wiktionary.org/wiki/felide :)

Ты еще и итальянец?

Че-там теперь с твоим фейспалмом?

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

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

Со мной все впорядке. Там могли быть идентификаторы, которые ты бы вообще не понял :) Для экономии места в иллюстрации идеи :)

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

Эт по латыни :) По инглишу таки Feline. А по-польшку пане ражмовляют? :)

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

Копипаст, как ты говоришь, иллюстрация идеи, как и отсутствие итераторов

не-не-не

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

но вообще лучше расскажи, зачем там трансформеры

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

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

Как в политегу запишем, так и будет. Никто никому ничо не должен :)

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

Не трансформеры, а трансформаторы... Для стеба над примером с розетками. Я стир. машины еще добавить хотел :)

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

// those push should be more complicated for index-safety of similar types like int and long

да, должны, поскольку никто тебе не мешает затолкать сначала cl.push_back(&t.intId), а затем затолкать в ту же цепь cl.push_back(&l.longId), и таким образом вместо отдельных двух цепей получить какую-то ернуду

ты вообще *как* думаешь решать эту проблему в рамках *своего* дизайна?

у меня, во втором варианте, она решалась просто: list->add(CHAIN1, s) и list->add(CHAIN2, s)

т.е. опять у тебя наблюдаются проблемы из-за замены наследования агрегацией

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

Это не проблемы :) Это интерфейсы методов push_back :) Их можно изменить так, что вот х*й ты туда положишь что-то кроме того, что требуется. Опять таки через полиси.

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

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

и где будет ошибка — в рантайме?

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

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

ты вообще *как* думаешь решать эту проблему в рамках *своего* дизайна?

дизаеном, как политегой, вполне может рулить пользователь :) Например, он может пушать не индексы(которые тут иллюстрируют идею не безопасно, но прозрачно), а индексируемые объекты в свои умные пуши - а пуши, которые более умные, будут из них дергать что надо :)

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

Эта круто чувак.

Пиши ещё. Там даже особо понимать эту портянку ненадо, достаточно увидеть:

i <= clSize-1
(i < clSize) == (i <= (clSize-1));

Потом, осиль указатели. Вам, индусам, реально чтоли за длинну портянки деньги платят?

перлы рода:

     LongIndex<Felide>* get_by_value(LongIndex<Felide>* first, long value)
	{
	  LongIndex<Felide>* ret = NULL;
	  for (LongIndex<Felide>* i=first; i!=NULL; i=i->next)
	  {
	    if (i->value == value) 
	    {
	      ret = i;
	      break;
	    }
	  }
	  return ret;
	}
Осиль писать не в индус стайле, перипеши на for, если первый иф не нравится. Добавь там != NULL, если так и не осилил синтаксис.
LongIndex<Felide>* get_by_value(LongIndex<Felide>* begin, long value) {
    if(!begin) return begin;
    while(begin->value != value && (begin = begin->next));
    return begin;
}
Осиль stdint.h, только днища юзают long, int и прочую фигню. C++ головного мозга.

Две верхние портянки мне даже лень читать и понимать.

o2n3e
()
Ответ на: Эта круто чувак. от o2n3e

Выбегалло прибежало :) Ты никак за мной охотишсо теперь? Что-то личное? :)

Две верхние портянки мне даже лень читать и понимать.

Твое ценное мнение очень важно для меня :) Но про лень... Бугурт тебя сюда привел, вопреки лени или Ц головного моска? Давай свой код - или трепло :) Пусть www_linux_org_ru просветится мудростью истинного гуру, который «не читал, но осуждаю».

(i < clSize) == (i <= (clSize-1));

не смеши людей, обфускатор сорцов :) Однострочники - это не круто. У тебя это пройдет.

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

обфускатор сорцов :)

while(begin->value != value && (begin = begin->next));

Тю... Я про этот кусок :)

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

Остерегись :) Он тебе еще про char * stuff [100500 * 100500] ; щас расскажет :) Настоящие ковбои ходят со взведенными заранее револьверами :)

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

Т.е. ты о5 слил?

Ты о5 не ответил на первый пример - раз.

не смеши людей, обфускатор сорцов :) Однострочники - это не круто. У тебя это пройдет.

Конечно, легко оправдать говнокод «боязнью однострочников». Ты небось и массивы перебираешь по индексу, и похрен, что это в «полтора раза» медленне? Или твая говнопортянка понятние, быстрее, «масштабируемей» и т.п. моего «однострочника» - нет, нет и нет.

Выбегалло прибежало :) Ты никак за мной охотишсо теперь? Что-то личное? :)

О5 как ребёнок слился. Нет, я читал тред, увидел портянку - увидел знакомую рожу и решил проверить, - «сольётся ли он о5», ибо я верю в сознательность людей.

(i < clSize) == (i <= (clSize-1));

Хоть с этим, горепортянщик, ты согласен?

Давай свой код - или трепло

Я тебе дал, с тебя хватит. Я уже писал в соседнет треде, что я не буду писать для вас абстрактные сущности. Давай конкретную задачу, а «напиши мне то, незнаю чё, но чтоб на шаблонах и как в С++» я уже проходил.

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

Надо найти елемент с value == 2-й аргумент - я написал код, который ДЕЛАЕТ ИМЕННО ЭТО, и ДЕЛАЕТ ЭТО ПОЧТИ МАКСИМАЛЬНО ОПТИМАЛЬНО. Твоя портянка работает на минимум 20-40% медленней, занимает в 10раз больше места и создают 10 лишних сущностей.

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

Очередной трололо-дно?

А теперь скопипасть ЦЕЛУЮ цитату, и авось до тебя дайдёт. Брысь горесливер из треда.

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

Основа основ.

Т.е. 2 хедера ты написал, 2 стандартный впилил, но 5-й тебе лень? Без разницы как ты это написал, такие перлы показывают то, как ты пишешь. О5 решил выехать из болота на ха-ха? Удачи.

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

Ещё кое что.

Только ненадо мне вонять, что твой либимый компилятор выкидывает мусор из твоего кода, как вы любите. Зачем ты пишешь мусор? Чтобы компилятор его выкидывал? Да и не особо-то он его выкидывает.

o2n3e
()
Ответ на: Очередной трололо-дно? от o2n3e

Настоящие ковбои ходят со взведенными заранее револьверами :)

...Из кобуры револьверы только не успевают достать :) Мушку спилил, детка?

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

Ничего ты не дал, только в лужу наметанил:) Можешь нас тут еще и жалкими ничтожными личностями назвать :) И побольше капса и «опасных меговысеров» (с) Задача выше по треду. Код или слил - ты :) Слоптимизация сорцов никому не нужна.

slackwarrior ★★★★★
()
Ответ на: Основа основ. от o2n3e

Мне было лень еще и итераторы писать :) И нейминг конвенцию соблюдать.

Удачи.

Оставь себе :) Статик буфера 100500*100500 хватит всем :)

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

он немного предсказуем :)

Но согласись, у парня есть стиль! Прелесть же.

while(begin->value != value && (begin = begin->next));

Или трогательная попытка сэкономить строку:

 if(!begin) return begin;
tailgunner ★★★★★
()
Ответ на: Т.е. и ты слил? от o2n3e

Отвечать на вас не учили?

Отвечать на кого? O_o Прими успокоительное и задай вопрос.

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