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...
Пока на собственное сообщение не было ответов, его можно удалить.