vector struct
От: Stals  
Дата: 26.03.10 19:17
Оценка:
struct Entry{
 std::string name;
 int number;
};

std::vector<Entry>book;

//во общем туда добавляются значения
//а перед выводом я хотел сделать сортировку по номеру телефона
int phoneSort(/*что мне передавать здесь?*/){
 struct Entry *ia=(struct Entry *)a;
 struct Entry *ib=(struct Entry *)b;
 return ia->number-ib->number;

}
main(){
 sort(book,bookLen,sizeof(struct Entry),phoneSort);

}

//bookLen увеличивается при добавлении новой записи

Может я еще что-то не так делаю..
добавил разметку — Кодт
vector struct
Re: vector struct
От: potapov.d  
Дата: 26.03.10 19:39
Оценка: +1 -1 :)
You do it wrong. Completely.

S> sort(book,bookLen,sizeof(struct Entry),phoneSort);


#include <algorithm>
#include <boost/bind.hpp>
...
std::sort(book.begin(), book.end(), boost::bind(&Entry::number, _1) < boost::bind(&Entry::number, _2));

phoneSort не нужен.
Re: vector struct
От: Alexey F  
Дата: 26.03.10 21:35
Оценка:
Здравствуйте, Stals, Вы писали:

S> sort(book,bookLen,sizeof(struct Entry),phoneSort);


Судя по имени — std::sort, судя по использованию — std::qsort (скорее, второе). Приведу примеры к обоим:
// Для qsort:
int phoneSort ( void const* left, void const* right ) {
    Entry const* leftEntry = static_cast<Entry const*> ( left ); // static_cast - более безопасный, нежели C-style cast ( struct Entry* )
    Entry const* rightEntry = static_cast<Entry const*> ( right );

    // -1, если меньше, 0, если равно и 1, если больше:
    if ( leftEntry->number < rightEntry->number ) {
        return -1;
    }
    else if ( leftEntry->number == rightEntry->number ) {
        return 0;
    }
    else {
        return 1;
    }
}


// Для std::sort:
struct SortByPhone {
    bool operator() ( Entry const& left, Entry const& right ) const {
        return left.number < right.number;
    }
};


#include <cstdlib> // для qsort
#include <algorithm> // для std::sort

// ...

std::vector<Entry> book;

int main () {
    // C-style:
    std::qsort ( &book[ 0 ], book.size (), sizeof ( Entry ), &phoneSort );

    // C++-style (рекомендую его):
    std::sort ( book.begin (), book.end (), SortByPhone () );
}


Re[2]: vector struct
От: strannik747  
Дата: 27.03.10 05:53
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF>
AF>struct SortByPhone {
AF>    bool operator() ( Entry const& left, Entry const& right ) const {
AF>        return left.number < right.number;
AF>    }
AF>};
AF>



А разве не так?
bool operator() ( const Entry& left, const Entry& right ) const {
Re[2]: vector struct
От: Centaur Россия  
Дата: 27.03.10 06:00
Оценка: 1 (1)
Здравствуйте, Alexey F, Вы писали:

AF>Судя по имени — std::sort, судя по использованию — std::qsort (скорее, второе). Приведу примеры к обоим:


Поскольку qsort — функция стандартной библиотеки C и не имеет информации о типе элементов сортируемого массива (а только о размере), следует предположить, что она обменивает элементы через memcpy или memmove. Следовательно, её нельзя применять к не-POD-типам. Структура Entry содержит член типа std::string, не являющийся POD-типом.
Re[2]: vector struct
От: Кодт Россия  
Дата: 27.03.10 08:10
Оценка: 1 (1)
Здравствуйте, Alexey F, Вы писали:

AF>Судя по имени — std::sort, судя по использованию — std::qsort (скорее, второе). Приведу примеры к обоим:


Не надо приводить примеры для qsort! Она не имеет права сортировать не-POD-ы, потому что вместо честного swap делает побайтовый обмен. А для std::string это может быть разрушительно.
Перекуём баги на фичи!
Re[3]: vector struct
От: Кодт Россия  
Дата: 27.03.10 08:41
Оценка: -1
К>Не надо приводить примеры для qsort! Она не имеет права сортировать не-POD-ы, потому что вместо честного swap делает побайтовый обмен. А для std::string это может быть разрушительно.

http://codepad.org/KfaVSMzf — пример того, как qsort разрушает инвариант объекта. (this->myself==this)
Перекуём баги на фичи!
Re[3]: vector struct
От: Alexey F  
Дата: 27.03.10 09:25
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Не надо приводить примеры для qsort! Она не имеет права сортировать не-POD-ы, потому что вместо честного swap делает побайтовый обмен. А для std::string это может быть разрушительно.

Упс, точно, там std::string
Извиняюсь, параллельно код на C писал и мне там массив char померещился
Re[3]: vector struct
От: Alexey F  
Дата: 27.03.10 09:27
Оценка:
Здравствуйте, strannik747, Вы писали:

S>А разве не так?

S>
S>bool operator() ( const Entry& left, const Entry& right ) const {
S>


const T& и T const& в данном случае (с указателями будут нюансы) эквивалентны, это вопрос привычки
Re[4]: vector struct
От: Кодт Россия  
Дата: 27.03.10 10:18
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF>const T& и T const& в данном случае (с указателями будут нюансы) эквивалентны, это вопрос привычки

Какие нюансы с указателями? const T* и T const* тоже идентичны.
Перекуём баги на фичи!
Re[5]: vector struct
От: Alexey F  
Дата: 27.03.10 11:10
Оценка:
Здравствуйте, Кодт, Вы писали:

AF>>const T& и T const& в данном случае (с указателями будут нюансы) эквивалентны, это вопрос привычки

К>Какие нюансы с указателями? const T* и T const* тоже идентичны.

// вторая версия сообщения[сегодня у меня явно не лады с разъяснениями]

T const* и const T* — конечно эквивалентны. Я имел ввиду:
const T*
T* const // не эквивалентны

Лично меня, когда я узнал впервые про "const справа" это запутало (как считал я вначале — "а, значит, просто переносим const вправо и всё работает"); Решив предупредить об этом человека, спросившего про
S>bool operator() ( const Entry& left, const Entry& right ) const {

это не расписал.
Re[4]: vector struct
От: skeptik_  
Дата: 27.03.10 22:28
Оценка:
Здравствуйте, Кодт, Вы писали:

К>>Не надо приводить примеры для qsort! Она не имеет права сортировать не-POD-ы, потому что вместо честного swap делает побайтовый обмен. А для std::string это может быть разрушительно.


К>http://codepad.org/KfaVSMzf — пример того, как qsort разрушает инвариант объекта. (this->myself==this)


искуственный пример. давайте пример как std::string разрушается.
Re[5]: vector struct
От: Кодт Россия  
Дата: 27.03.10 22:48
Оценка:
Здравствуйте, skeptik_, Вы писали:

_>искуственный пример. давайте пример как std::string разрушается.


Запросто. Только на экзотических версиях STL.
Если string содержит буфер для маленькой строки сама в себе, и указатель на буфер — встроенный или внешний.
class string
{
  char *m_begin;
  size_t m_size, m_capacity;
  char m_buffer[BUFSIZE];

public:
  .....
};

После побайтового обмена — содержимое буферов обменяется, это правильно, но заодно — строки будут ссылаться не на свои буферы, а перекрёстно. Дальнейшая судьба объектов со сломанным инвариантом туманна и грустна.
Перекуём баги на фичи!
Re[6]: vector struct
От: skeptik_  
Дата: 27.03.10 22:54
Оценка:
Здравствуйте, Кодт, Вы писали:

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


_>>искуственный пример. давайте пример как std::string разрушается.


К>Запросто. Только на экзотических версиях STL.


Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.
Re[7]: vector struct
От: Erop Россия  
Дата: 27.03.10 23:34
Оценка:
Здравствуйте, skeptik_, Вы писали:

_>Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.


Не такой уж и искусственный. С MSVC вроде как одно время поставлялся STL с такой строкой...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: vector struct
От: Кодт Россия  
Дата: 28.03.10 07:41
Оценка: +1
Здравствуйте, skeptik_, Вы писали:

К>>Запросто. Только на экзотических версиях STL.


_>Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.


Это не искусственный пример. Я с таким стрингом работал.
Внутренний буфер резко увеличивает производительность, снимая нагрузку с менеджера памяти.
Перекуём баги на фичи!
Re[8]: vector struct
От: skeptik_  
Дата: 28.03.10 09:26
Оценка:
Здравствуйте, Erop, Вы писали:

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


_>>Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.


E>Не такой уж и искусственный. С MSVC вроде как одно время поставлялся STL с такой строкой...


Он до сих поставляется со small string optimization. Только делается она не столь нелепо, а через union указателя на внешний buffer и внутреннего buffer.
Re[8]: vector struct
От: skeptik_  
Дата: 28.03.10 09:27
Оценка: -2
Здравствуйте, Кодт, Вы писали:

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


К>>>Запросто. Только на экзотических версиях STL.


_>>Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.


К>Это не искусственный пример. Я с таким стрингом работал.


Это конечно не исключено, что какой-то ССЗБ такое написал, но обычно это делается через юнион.
Re[9]: vector struct
От: Кодт Россия  
Дата: 28.03.10 10:06
Оценка:
Здравствуйте, skeptik_, Вы писали:

_>Это конечно не исключено, что какой-то ССЗБ такое написал, но обычно это делается через юнион.


Не ССЗБ, а тщательное профилирование.
Устойчивость к говнокоду не требовалась.
Перекуём баги на фичи!
Re[3]: vector struct
От: Тролль зеленый и толстый  
Дата: 28.03.10 12:41
Оценка: +1
C>Поскольку qsort — функция стандартной библиотеки C и не имеет информации о типе элементов сортируемого массива (а только о размере), следует предположить, что она обменивает элементы через memcpy или memmove. Следовательно, её нельзя применять к не-POD-типам. Структура Entry содержит член типа std::string, не являющийся POD-типом.

Кстати, распространенное заблуждение. POD здесь не при чем. Здесь важно лишь можно ли объект перемещать в памяти или нет. Существуют не POD-типы, которые можно перемещать, и POD-типы, которые нельзя перемещать (например, если в структуре имеется указатель, указывающий на одно из полей этой же структуры). Можно ли перемещать std::string, зависит от его реализации, вполне может быть, что можно.
Re[7]: vector struct
От: Bell Россия  
Дата: 29.03.10 02:27
Оценка:
Здравствуйте, skeptik_, Вы писали:

К>>Запросто. Только на экзотических версиях STL.


_>Ещё один искуственный пример skipped. Нормального примера не будет, насколько я понимаю.


STLPort 5.2.1, оптимизация коротких строк включена — ИМХО совсем не экзотическая реализация. Падает при работе в отладчике при разрушении вектора на таком примере:

struct Entry{
 std::string name;
 int number;
};

int phoneSort ( void const* left, void const* right ) {
    Entry const* leftEntry = static_cast<Entry const*> ( left ); // static_cast - более безопасный, нежели C-style cast ( struct Entry* )
    Entry const* rightEntry = static_cast<Entry const*> ( right );

    // -1, если меньше, 0, если равно и 1, если больше:
    if ( leftEntry->number < rightEntry->number ) {
        return -1;
    }
    else if ( leftEntry->number == rightEntry->number ) {
        return 0;
    }
    else {
        return 1;
    }
}


int main()
{
   std::vector<Entry> book;
   Entry e1 = {"222222222222222222", 2};
   Entry e2 = {"1", 1};
   book.push_back(e1);
   book.push_back(e2);

   std::qsort ( &book[ 0 ], book.size (), sizeof ( Entry ), &phoneSort );

   return 0;
}
Любите книгу — источник знаний (с) М.Горький
Re[4]: vector struct
От: Centaur Россия  
Дата: 29.03.10 08:25
Оценка:
Здравствуйте, Тролль зеленый и толстый, Вы писали:

C>>Поскольку qsort — функция стандартной библиотеки C и не имеет информации о типе элементов сортируемого массива (а только о размере), следует предположить, что она обменивает элементы через memcpy или memmove. Следовательно, её нельзя применять к не-POD-типам. Структура Entry содержит член типа std::string, не являющийся POD-типом.


ТЗИ>Кстати, распространенное заблуждение. POD здесь не при чем. Здесь важно лишь можно ли объект перемещать в памяти или нет. Существуют не POD-типы, которые можно перемещать, и POD-типы, которые нельзя перемещать (например, если в структуре имеется указатель, указывающий на одно из полей этой же структуры). Можно ли перемещать std::string, зависит от его реализации, вполне может быть, что можно.


В действующем стандарте 2003 (выделены изменения между 2003 и 0x):

3.9 Types [basic.types]

2: For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char.[36] If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value. [example/]

3: For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the value of obj1 is copied into obj2, using the memcpy library function, obj2 shall subsequently hold the same value as obj1. [example/]


В стандартопроекте C++0x, n3035:

3.9 Types [basic.types]

2: For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char.[39] If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value. [example/]

3: For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making up obj1 are copied into obj2,[40] obj2 shall subsequently hold the same value as obj1. [example/]

40) By using, for example, the library functions (17.6.1.2) std::memcpy or std::memmove.


Далее:

3.9/9: Scalar types, trivially copyable class types (Clause 9), arrays of such types, and cv-qualified versions of these types (3.9.3) are collectively called trivially copyable types.

9/5: A trivially copyable class is a class that:


12.8/6: A copy constructor for class X is trivial if it is not user-provided (8.4) and if
otherwise the copy constructor is non-trivial.

12.8/13 A copy assignment operator for class X is trivial if it is not user-provided and if

12.4/3: […] A destructor is trivial if it is not user-provided and if:
An implicitly-declared destructor for a class X is defined as deleted if:
Otherwise, the destructor is non-trivial.


Далее, 21.4 перечисляет copy constructor, copy assignment operator и destructor. Все они, насколько я могу интерпретировать, относятся к user-provided и, следовательно, non-trivial. Таким образом, std::string (и любой класс, включающий std::string в качестве базы или члена) не является trivially copyable, следовательно, стандарт не гарантирует, что сортировка массива таких объектов через qsort будет корректна.

Кроме того, стандартопроект C++0x в 25.5/4 гласит:

25.5/4: The function signature:

qsort(void *, size_t, size_t, int (*)(const void *, const void *));

is replaced by the two declarations:
extern "C" void qsort(void* base, size_t nmemb, size_t size,
                      int (*compar)(const void*, const void*));
extern "C++" void qsort(void* base, size_t nmemb, size_t size,
                        int (*compar)(const void*, const void*));

both of which have the same behavior as the original declaration. The behavior is undefined unless the objects in the array pointed to by base are of trivial type.

— то есть налагается ограничение даже более сильное, чем trivially copyable type:

3.9/9: […] Scalar types, trivial class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called trivial types.

9/5: A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.

Re[5]: vector struct
От: Кодт Россия  
Дата: 29.03.10 13:38
Оценка:
Здравствуйте, Centaur, Вы писали:

ТЗИ>>Кстати, распространенное заблуждение. POD здесь не при чем. Здесь важно лишь можно ли объект перемещать в памяти или нет. Существуют не POD-типы, которые можно перемещать, и POD-типы, которые нельзя перемещать (например, если в структуре имеется указатель, указывающий на одно из полей этой же структуры). Можно ли перемещать std::string, зависит от его реализации, вполне может быть, что можно.


C>В действующем стандарте 2003 (выделены изменения между 2003 и 0x):

<...>

В общем-то, это буквоедство и дефектоскопия. В 2003 используется расширенное требование, POD, а в 0x — более узкое, trivally copyable.
А суть та же самая: если объект нетривиально копируется/присваивается/обменивается, то не надо его тривиально (побайтно) копировать/присваивать/обменивать
Даже если конкретный стандарт (2003) об этом умалчивает, всё равно "Нургалиев разрешил" является антипаттерном
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.