powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / sizeof( strcuct {string} )?
46 сообщений из 46, показаны все 2 страниц
sizeof( strcuct {string} )?
    #39608171
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не, я конечно давно знаю что если хочешь сортировать объекты с переменной длинной, то сортируй указатели на них.
Но.... разве класс string не является сам по себе указателем на данные?
Да даже если оно хранит данные напрямую в структуре и Record.s на самом деле переменной длины, почему тогда значение целого не портится?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
#include <string>
#include <cstdlib>
#include <array>
#include <iostream>

using namespace std;

struct Record {
	string s;
	int i;
};

int main(int argc, char **argv) {
	array<Record, 5> arr;
	arr[0].s = "qwe";
	arr[1].s = "ertyu";
	arr[2].s = "dfgcvb";
	arr[3].s = "a";
	arr[4].s = "fhuj";

	arr[0].i = 4;
	arr[1].i = 2;
	arr[2].i = 3;
	arr[3].i = 0;
	arr[4].i = 1;

	cout << "original\n";
	for(auto r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by int\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			if (ap->i < bp->i) return -1;
			if (ap->i > bp->i) return 1;
			return 0;
		}
	);
	for(auto r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by string\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			return ap->s.compare(bp->s);
		}
	);
	for(auto r:arr) cout << r.s << ' ' << r.i << "\n";

	return 0;
}

...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608179
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
При использовании в C++, функция qsort по много раз уничтожает объект (вызывает деструктор у Record и у std::string) и копирует указатель на освобожденную память, поэтому ваш код просто будет падать с Seg Fault.

Потому что для классов из C++ (struct вызывающих деструктор) надо использовать std::sort из C++, а не qsort-из C.
Код: plaintext
1.
2.
3.
4.
5.
6.
	std::sort(arr.begin(), arr.end(),
		[]( Record a,  Record b) -> bool {
			if (a.i < b.i) return true;
			return false;
		}
	);
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608193
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася Уткин,

не подтверждаю.

qsort не знает ничего о сортируемом объекте, С++ не дает такой инфы.

исправленный пример и вывод
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
#include <string>
#include <cstdlib>
#include <array>
#include <iostream>

using namespace std;

struct Record {
	~Record(){ cout << i << "-destructs"<< endl; }
	string s;
	int i;
};

int main(int argc, char **argv) {
	array<Record, 5> arr;
	arr[0].s = "qwe";
	arr[1].s = "ertyu";
	arr[2].s = "dfgcvb";
	arr[3].s = "a";
	arr[4].s = "fhuj";

	arr[0].i = 4;
	arr[1].i = 2;
	arr[2].i = 3;
	arr[3].i = 0;
	arr[4].i = 1;

	cout << "original\n";
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by int\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			if (ap->i < bp->i) return -1;
			if (ap->i > bp->i) return 1;
			return 0;
		}
	);
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by string\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			return ap->s.compare(bp->s);
		}
	);
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	return 0;
}


zoriginal
qwe 4
ertyu 2
dfgcvb 3
a 0
fhuj 1

qsort by int
a 0
fhuj 1
ertyu 2
dfgcvb 3
qwe 4

qsort by string
a 0
dfgcvb 3
ertyu 2
fhuj 1
qwe 4
4-destructs
1-destructs
2-destructs
3-destructs
0-destructs
gcc 4.9.2

отдыхать надо, среда скоро
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608217
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SiemarglВася Уткин,

не подтверждаю.

qsort не знает ничего о сортируемом объекте, С++ не дает такой инфы.

исправленный пример и вывод
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
#include <string>
#include <cstdlib>
#include <array>
#include <iostream>

using namespace std;

struct Record {
	~Record(){ cout << i << "-destructs"<< endl; }
	string s;
	int i;
};

int main(int argc, char **argv) {
	array<Record, 5> arr;
	arr[0].s = "qwe";
	arr[1].s = "ertyu";
	arr[2].s = "dfgcvb";
	arr[3].s = "a";
	arr[4].s = "fhuj";

	arr[0].i = 4;
	arr[1].i = 2;
	arr[2].i = 3;
	arr[3].i = 0;
	arr[4].i = 1;

	cout << "original\n";
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by int\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			if (ap->i < bp->i) return -1;
			if (ap->i > bp->i) return 1;
			return 0;
		}
	);
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by string\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			return ap->s.compare(bp->s);
		}
	);
	for(const auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	return 0;
}


zoriginal
qwe 4
ertyu 2
dfgcvb 3
a 0
fhuj 1

qsort by int
a 0
fhuj 1
ertyu 2
dfgcvb 3
qwe 4

qsort by string
a 0
dfgcvb 3
ertyu 2
fhuj 1
qwe 4
4-destructs
1-destructs
2-destructs
3-destructs
0-destructs
gcc 4.9.2

отдыхать надо, среда скоро
А давно ли чисто сишный qsort() на вход стал принимать итераторы из C++, вместо указателей?

1. Сначала переписывайте с arr.begin() на &arr[0]
2. Затем меняйте static_cast<const Record*>(a); на reinterpret_cast<const Record*>(a);
3. Теперь получайте SegFault и удивляйтесь :)
4. Убирайте временно string s из Record и добавляйте в Record деструктор с выводом сообщения
5. Профит
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608219
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Siemarglgcc 4.9.2

отдыхать надо, среда скорохмммм... У тебя строки не портятся.

Так. Подправлю код чтобы было лучше видно:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
#include <string>
#include <cstdlib>
#include <array>
#include <iostream>

using namespace std;

struct Record {
	string s;
	int i;
	~Record(){ cout << "-destructs " << s << ' ' << i << "\n"; }
};

int main(int argc, char **argv) {
	array<Record, 5> arr;
	arr[0].s = "red";
	arr[1].s = "green grass";
	arr[2].s = "magenta ball";
	arr[3].s = "black";
	arr[4].s = "gray goose with long neck";

	// uncomment this to fix the output.
	// for(auto &r:arr) r.s.reserve(32);  

	arr[0].i = 4;
	arr[1].i = 2;
	arr[2].i = 3;
	arr[3].i = 0;
	arr[4].i = 1;

	cout << "original\n";
	for(auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by int\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			if (ap->i < bp->i) return -1;
			if (ap->i > bp->i) return 1;
			return 0;
		}
	);
	for(auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	cout << "\nqsort by string\n";
	qsort(arr.begin(), arr.size(), sizeof(Record),
		[](const void* a, const void* b) {
			const Record *ap = static_cast<const Record*>(a);
			const Record *bp = static_cast<const Record*>(b);
			return ap->s.compare(bp->s);
		}
	);
	for(auto &r:arr) cout << r.s << ' ' << r.i << "\n";

	return 0;
}


И вывод очень странный:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
original
red 4
green grass 2
magenta ball 3
black 0
gray goose with long neck 1

qsort by int
magen 0
gray goose with long neck 1
▲   m∟@ á∟@ 2
green grass  3
bla 4

qsort by string
▲   m∟@ á∟@ 2
gray goose with long neck 1
magenta ball 3
gre 4
red ♦ 0
-destructs red ♦ 0
-destructs gre 4
-destructs magenta ball 3
-destructs gray goose with long neck 1
-destructs ▲   m∟@ á∟@ 2

Я собираю на 5.3.0 на винде.

А если после создания строк добавить for(auto &r:arr) r.s.reserve(32); (оно там закоментировано сейчас). То все становится замечательно.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608224
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Начиная с GCC 5.1.0 уже падает с ошибкой памяти: https://wandbox.org/permlink/SDDOPMgBqGjgLfT7

На clang везде где компилируется с 3.5.0 по Head 7.0 - работает нормально: https://wandbox.org/permlink/qNn1lnocaiHEab4W

Ну и на винде судя по всему работает, но неправильно - портит символы. Вот они грязные хаки к чему приводят )
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608232
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася регайся. Чорт тебя подери
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608233
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася Уткин,

нет там грязных хаков.

надо брвть норм версию компилятора, а не говнобету 5.1, и разбираться
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608241
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonВася регайся. Чорт тебя подери
Пока без багов писать не начнёте не зарегюсь
SiemarglВася Уткин,

нет там грязных хаков.

надо брвть норм версию компилятора, а не говнобету 5.1, и разбираться
Siemargl
Код: plaintext
1.
2.
3.
array<Record, 5> arr;
//...
	qsort(arr.begin(), arr.size(), sizeof(Record), 


Вопрос, что надо передать в qsort: результат функции begin() или data()?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf Page 480
21.2.2 Header <cstdlib> synopsis
// 28.8, C standard library algorithms
void qsort( void* base, size_t nmemb, size_t size, c-compare-pred * compar);
void qsort( void* base, size_t nmemb, size_t size, compare-pred * compar);
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf Page 1049
28.8 C library algorithms
void qsort( void* base, size_t nmemb, size_t size, c-compare-pred * compar);
void qsort( void* base, size_t nmemb, size_t size, compare-pred * compar);
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf Page 872
26.3.7.1 Class template array overview
// iterators:
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;

constexpr T * data() noexcept;
constexpr const T * data() const noexcept;
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608485
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White OwlА если после создания строк добавить for(auto &r:arr) r.s.reserve(32); (оно там закоментировано сейчас). То все становится замечательно.
Очевидно же, что это все из-за small string optimization в std::string начиная с gcc 5.1, т.к. сишный qsort() использует memcpy() вместо operator=() и конструктора.
В общем грязные хаки такие как передавать итератор вместо указателя или использовать сишный qsort() для классов с конструкторами и операторами копирования ни к чему хорошему не приводят.

https://isocpp.org/blog/2015/04/gcc-5.1-released GCC 5.1 released
A new implementation of std::string is enabled by default, using the small string optimization
instead of copy-on-write reference counting.

Что будет если запустить такой код? https://wandbox.org/permlink/9pfxYTio5N2mK6yH
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
#include <string>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <array>
#include <iostream>

struct small_str_opt {
 char buff[16];
 char *ptr;
 size_t length;
 small_str_opt() : length(0), ptr(buff) {}
 small_str_opt(char const* src) {
  length = strlen(src);
  if(length<= 16) ptr = buff;
  else ptr = (char *)malloc(length); 
  memcpy(ptr, src, length);
 }
 small_str_opt operator=(small_str_opt const& src) {
   if(src.length > length) {
    if(length > 16) free(ptr);
    if(src.length > 16) ptr = (char *)malloc(src.length);
   }
   length = src.length;
   memcpy(ptr, src.ptr, length);
 }
  ~small_str_opt() { if(length > 16) free(ptr); }
};

std::ostream& operator<< (std::ostream& out, small_str_opt const val) {
  for(size_t i = 0; i < val.length; ++i) out << val.ptr[i];
  return out;
}

int main() {
 small_str_opt s1 = "qwert", s2 = "ab", s_tmp;
 std::cout << "In: s1 = " << s1 << ", s2 = " << s2 << std::endl;
    
/*
 // std::sort
 s_tmp = s1;
 s1 = s2;
 s2 = s_tmp;
 std::cout << "op=(): s1 = " << s1 << ", s2 = " << s2 << std::endl;
*/   
    
 // qsort()
 memcpy(&s_tmp, &s1, sizeof(small_str_opt));
 memcpy(&s1, &s2, sizeof(small_str_opt));
 memcpy(&s2, &s_tmp, sizeof(small_str_opt));
    
 // damaged strings
 std::cout << "Out: s1 = " << s1 << ", s2 = " << s2 << std::endl;

 return 0;
}
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608495
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася Уткин,

плохо. падает прозрачность языка

в целом это негативно сказывается на производительности

да и на понимаемости. см топик и 21223495 =)
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608497
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Siemarglв целом это негативно сказывается на производительности
А можно по конкретней, как small string optimization плохо сказывается на производительности?
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608620
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинSiemarglв целом это негативно сказывается на производительности
А можно по конкретней, как small string optimization плохо сказывается на производительности?
вот же и пример - сортировать "в лоб" нельзя, копирование будет медленнее (особенно массивов строк)

но я имел в виду больше - сокрытие деталей "под капотом" мешает пониманию - что же на самом деле происходит, ну и конечно как писать оптимальный код, если непонятны накладные расходы
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608696
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SiemarglВася Уткинпропущено...

А можно по конкретней, как small string optimization плохо сказывается на производительности?
вот же и пример - сортировать "в лоб" нельзя, копирование будет медленнее (особенно массивов строк)

но я имел в виду больше - сокрытие деталей "под капотом" мешает пониманию - что же на самом деле происходит, ну и конечно как писать оптимальный код, если непонятны накладные расходы
Насчет понимания кода под копотом - согласен. Я понимал, что дело в memcpy() вместо operator=(), т.е. qsort не предназначен для C++-struct/class, но сначала подумал на деструктор временной переменной используемой для обмена местами двух элементов, а присмотревшись понял, что дело в small string optimization, а не в деструкторе.

А почему сортировка будет медленней? На GCC 4.9.2 (без smo) std::string занимает 8 байт, а на GCC 5.1.0 (с smo) std::string занимает 32 байта. Но CPU читает данные из памяти сразу кэш-линиями по 64 байта:
- В gcc 4.9.2 всегда надо прочитать как минимум 2 кэш-линии и автоматический префетч кэша не поможет, т.к. каждый динамически аллоцируемый участок не расположен строго один за другим.
- А в gcc 5.1.0 во многих случаях достаточно прочитать 1 кэш линию и плюс автоматический префетч загрузит все ближайшие элементы массива в кэш, т.к. они расположены последовательно.

И ладно, допустим, что smo - это шляпа. Но правильно ли использовать qsort() для C++-struct/class?
Самое главное - в каждой конкретной задаче разработчик может захотеть сделать свои оптимизации в конструкторе и operator(), которые в его задаче точно нужны, и использование qsort() сломает код, а std::sort() не сломает.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608698
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинВопрос, что надо передать в qsort: результат функции begin() или data()? С совсем формальной точки зрения - array<>::data().
Но учитывая что речь идет про array<>, а его итерторы это простые указатели. Так что в данном конкретном случае begin() и data() фактически одно и то-же.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608711
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Читал топик, ломал голову что могло сглючить из-за memcpy()

Придумал один вариант и он подтвердился
Вася Уткин
Код: plaintext
1.
2.
3.
4.
5.
struct small_str_opt {
 char buff[16];
 char *ptr;
...
  if(length<= 16) ptr = buff;
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608789
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White OwlВася УткинВопрос, что надо передать в qsort: результат функции begin() или data()? С совсем формальной точки зрения - array<>::data().
Но учитывая что речь идет про array<>, а его итерторы это простые указатели. Так что в данном конкретном случае begin() и data() фактически одно и то-же.
Фактически это: auto it = arr.begin(); Record *ptr = *reinterpret_cast<Record **>(&it);
Пока что да - указатель, но когда то и std::string был просто указателем на данные )
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608843
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинПри использовании в C++, функция qsort по много раз уничтожает объект (вызывает деструктор у Record и у std::string) и копирует указатель на освобожденную память, поэтому ваш код просто будет падать с Seg Fault.

Потому что для классов из C++ (struct вызывающих деструктор) надо использовать std::sort из C++, а не qsort-из C.
Код: plaintext
1.
2.
3.
4.
5.
6.
	std::sort(arr.begin(), arr.end(),
		[]( Record a,  Record b) -> bool {
			if (a.i < b.i) return true;
			return false;
		}
	);



Ничего не должно тут падать.
Но падает.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39608844
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl,

А вот нафига же тебе там void* ?
Когда ну всё уже сделано в С++ чтобы все указатели были типизированы.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39609356
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivWhite Owl,

А вот нафига же тебе там void* ?
Когда ну всё уже сделано в С++ чтобы все указатели были типизированы.Мне??? Это вообще-то требование библиотечной функции std::qsort() .
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39609414
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TЧитал топик, ломал голову что могло сглючить из-за memcpy()

Придумал один вариант и он подтвердился
Вася Уткин
Код: plaintext
1.
2.
3.
4.
5.
struct small_str_opt {
 char buff[16];
 char *ptr;
...
  if(length<= 16) ptr = buff;



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

Там должен быть union в типизационной обертке
char* operator()
или
const char* operator()

если нужно передавать в функцию требующую void*
то конечно же тип нужно явыным образом привести под
неявный вызов operator().
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611559
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlНе, я конечно давно знаю что если хочешь сортировать объекты с переменной длинной, то сортируй указатели на них.
Но.... разве класс string не является сам по себе указателем на данные?
Да даже если оно хранит данные напрямую в структуре и Record.s на самом деле переменной длины, почему тогда значение целого не портится?


Пару раз прочитал, не очень понятно. Почему при сортировке с использованием стандартных функций С и С++ мы можем ожидать в качестве побочного эффекта изменение сортируемых объектов?
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611563
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryWhite OwlНе, я конечно давно знаю что если хочешь сортировать объекты с переменной длинной, то сортируй указатели на них.
Но.... разве класс string не является сам по себе указателем на данные?
Да даже если оно хранит данные напрямую в структуре и Record.s на самом деле переменной длины, почему тогда значение целого не портится?


Пару раз прочитал, не очень понятно. Почему при сортировке с использованием стандартных функций С и С++ мы можем ожидать в качестве побочного эффекта изменение сортируемых объектов?
Ах да, надо бы разъяснить.

Строка переместилась, но она содержала указатель на себя, который остался указывать на старое место.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611611
Barlone
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryWhite OwlНе, я конечно давно знаю что если хочешь сортировать объекты с переменной длинной, то сортируй указатели на них.
Но.... разве класс string не является сам по себе указателем на данные?
Да даже если оно хранит данные напрямую в структуре и Record.s на самом деле переменной длины, почему тогда значение целого не портится?


Пару раз прочитал, не очень понятно. Почему при сортировке с использованием стандартных функций С и С++ мы можем ожидать в качестве побочного эффекта изменение сортируемых объектов?

Так написано же:
Код: plaintext
  "The type of the elements of the array must be a  TrivialType , otherwise the behavior is undefined."
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611623
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryПару раз прочитал, не очень понятно. Почему при сортировке с использованием стандартных функций С и С++ мы можем ожидать в качестве побочного эффекта изменение сортируемых объектов?
Наоборот: объекты не меняются, но должны, т.к. внутри string буфер и указатель на этот буфер.
Выше пример кода который сглючит 21224926 и 21226275
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611749
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TSashaMercuryПару раз прочитал, не очень понятно. Почему при сортировке с использованием стандартных функций С и С++ мы можем ожидать в качестве побочного эффекта изменение сортируемых объектов?
Наоборот: объекты не меняются, но должны, т.к. внутри string буфер и указатель на этот буфер.
Выше пример кода который сглючит 21224926 и 21226275

Ничего там ломаться не должно:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
#define DEFBUFFSZ 16

union mbuffs
{
char  fbuff[DEFBUFFSZ];
char* vbuff;
};

class sbuffs
{
mbuffs s_str;        // buffer
unsigned int s_size;
.....


inline  operator char*()    
      {     
       if(s_size>=DEFBUFFSZ-1)
               return s_str.vbuff;
       return &s_str.fbuff[0];
       };
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611909
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
д0kХ
Код: plaintext
1.
2.
3.
4.
5.
6.
inline  operator char*()    
      {     
       if(s_size>=DEFBUFFSZ-1)
               return s_str.vbuff;
       return &s_str.fbuff[0];
       };



Так ИМХО будет оптимальнее, если стековую строку дефайнить на не менее чем
на 2 машинных слова.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
inline  operator char*()    
      {     
        switch  ( s_str.fbuff[DEFBUFFSZ-1] )
          {
          case '0xFF':  return  s_str.vbuff;        break; 
          case  '0х00':  return &s_str.fbuff[0];  break; 
          default : throw  internal_mem_corruption;
        };
       };



Не проверял .
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611937
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
д0kХ,

if (или switch) могут влиять на процессорные оптимизации, поэтому указатель желательно хранить уже вычисленным.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611938
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если уж делать позиционно независимые строки, то вместо указателя можно хранить смещение к нему относительно this
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611948
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyЕсли уж делать позиционно независимые строки, то вместо указателя можно хранить смещение к нему относительно this
Вот меня удивляет, почему в gcc так не сделали.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611951
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
д0kХНичего там ломаться не должно:
Код: plaintext
1.
2.
3.
4.
5.
6.
inline  operator char*()    
      {     
       if(s_size>=DEFBUFFSZ-1)
               return s_str.vbuff;
       return &s_str.fbuff[0];
       };


Да, так не сломается, но так работает быстрее
Код: plaintext
1.
2.
3.
4.
inline  operator char*()    
      {     
               return s_str.vbuff;
       };
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611953
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyЕсли уж делать позиционно независимые строки, то вместо указателя можно хранить смещение к нему относительно this
Не поможет, т.к. для больших строк выделение памяти через malloc(), т.е. за пределами объекта.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611957
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TНе поможет, т.к. для больших строк выделение памяти через malloc(), т.е. за пределами объекта.
Так смещение тоже может указывать за пределы объекта )))
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611960
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинВот меня удивляет, почему в gcc так не сделали.
Потому что такие строки все равно никому не нужны.
Как выше написали все равно такое использование строк - UB
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611964
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovskyд0kХ,

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

Он вычислен
начало массива лежащего в стеке, преобразуется в
указатель на строку через ссылку на нулевой элемент.
либо из самого массива берется указатель.
В зависимости от длины строки возвращается либо то либо другое.
Что бы не хранить размер ( сэкономить sizeof(int) на каждом элементе массива строк
в последенм примере в последнем байте массива строки фиксированной длины
хранится либо 0х00 как в последеднем байте любой строки.
либо 0хFF если первое слово в массие является указателем на строку.

Если не то и не другое , значит кто то покоцал память .
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611968
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima Tд0kХНичего там ломаться не должно:
Код: plaintext
1.
2.
3.
4.
5.
6.
inline  operator char*()    
      {     
       if(s_size>=DEFBUFFSZ-1)
               return s_str.vbuff;
       return &s_str.fbuff[0];
       };


Да, так не сломается, но так работает быстрее
Код: plaintext
1.
2.
3.
4.
inline  operator char*()    
      {     
               return s_str.vbuff;
       };



Быстрее оно до тех пор, пока вы
не присумируете туда время 100500 вызовов new и delete
для строк меньше 16 байт.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611973
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
д0kХAnatoly Moskovskyд0kХ,

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

Он вычислен .
if/switch - это и есть вычисления для предсказателя переходов, причем с учетом ошибок предсказания - это статистически очень долгие операции.

Весь вопрос в том, где лучше оставить if/switch:
- либо в operator char*() , как у вас
- либо в operator=(), как я приводил пример и как видимо у gcc 5.1 (раз у них ломается)

Что реже вызывается, там и надо оставлять. Видимо в GCC посчитали, что объект меняется реже, чем читается (или меняются только отдельные ячейки строки).
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611981
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вася УткинВесь вопрос в том, где лучше оставить if/switch:
- либо в operator char*() , как у вас
- либо в operator=(), как я приводил пример и как видимо у gcc 5.1 (раз у них ломается)

Что реже вызывается, там и надо оставлять. Видимо в GCC посчитали, что объект меняется реже, чем читается (или меняются только отдельные ячейки строки).
В присвоении по любому этот if есть ))
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611988
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вася Уткинд0kХпропущено...


Он вычислен .
if/switch - это и есть вычисления для предсказателя переходов, причем с учетом ошибок предсказания - это статистически очень долгие операции.

Весь вопрос в том, где лучше оставить if/switch:
- либо в operator char*() , как у вас
- либо в operator=(), как я приводил пример и как видимо у gcc 5.1 (раз у них ломается)

Что реже вызывается, там и надо оставлять. Видимо в GCC посчитали, что объект меняется реже, чем читается (или меняются только отдельные ячейки строки).


Вычислен это как минумум одно лишнее машинное слово в классе.
И это где то 50 % размера строки.

Сейчас оперативную память наверное никто не считает.

Но мне очень кажется, что десяток тактов процессра дешевле
одного машинного слова метаданных в ОЗУ .

ВСЕ ИМХО

Как думают создатели GCC мне не ведомо.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39611999
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В случае со switch и расчетом на лету
в кеше процессора поместится гораздо больше элементов массива строк.
чем с предрасчитанным и хранящимся в отдельном поле класса указателем.


по хорошему тестить надо.

В топик вызывается Майтон :)
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612001
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
д0kХВася Уткинпропущено...

if/switch - это и есть вычисления для предсказателя переходов, причем с учетом ошибок предсказания - это статистически очень долгие операции.

Весь вопрос в том, где лучше оставить if/switch:
- либо в operator char*() , как у вас
- либо в operator=(), как я приводил пример и как видимо у gcc 5.1 (раз у них ломается)

Что реже вызывается, там и надо оставлять. Видимо в GCC посчитали, что объект меняется реже, чем читается (или меняются только отдельные ячейки строки).


Вычислен это как минумум одно лишнее машинное слово в классе.
И это где то 50 % размера строки.

Сейчас оперативную память наверное никто не считает.

Но мне очень кажется, что десяток тактов процессра дешевле
одного машинного слова метаданных в ОЗУ .

ВСЕ ИМХО

Как думают создатели GCC мне не ведомо.
Чем новее процессор, тем в нем больше суперскалярных ALU-ports, и тем больше ALU будут простаивать при ошибке предсказания перехода. А кэш и память увеличиваются (за исключением L1), так что в перспективе думаю выгоднее больше памяти затратить.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612018
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вася Уткинд0kХпропущено...



Вычислен это как минумум одно лишнее машинное слово в классе.
И это где то 50 % размера строки.

Сейчас оперативную память наверное никто не считает.

Но мне очень кажется, что десяток тактов процессра дешевле
одного машинного слова метаданных в ОЗУ .

ВСЕ ИМХО

Как думают создатели GCC мне не ведомо.
Чем новее процессор, тем в нем больше суперскалярных ALU-ports, и тем больше ALU будут простаивать при ошибке предсказания перехода. А кэш и память увеличиваются (за исключением L1), так что в перспективе думаю выгоднее больше памяти затратить.

Понятное дело .

Я лет 15-20 назад, когда это писал
решал конкретную практическую задачу минимизации вызовов аллокации - деаллокации памяти
для коротких строк.
но некоторый небольшой % строк в массивах могли быть длинными.

Если у автора топика есть разумное ограничение на длину строки,
то задача решится достаоточно просто, без забивания саморезов микроскопом.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612214
Siemarglнет там грязных хаков.
Да. Есть всего лишь UB.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612224
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот Вася. А я вить предупреждал.
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612231
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonНу вот Вася. А я вить предупреждал.
Скоро у меня будет целая секта с блекджеком и последователями
...
Рейтинг: 0 / 0
sizeof( strcuct {string} )?
    #39612353
д0кХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyЕсли уж делать позиционно независимые строки, то вместо указателя можно хранить смещение к нему относительно this

Это уже база данных.

Там в блоке данных, хранящемся на диске
записи хранятся как попало и пракитчески любой длины
и в любом количестве .
Но в блоке есть массив смещений записей от начала блока.
Глобально запись адресуется номером ( смещением) блока от начала
датафайла и индексом массиве блока.

Эта сущьсность в БД называется rowid .

Зная rowid любую запись можно достать с диска
за одну операцию чтения 2-е коственных адресации .
по этому принципу прострен индексный поиск в БД.
...
Рейтинг: 0 / 0
46 сообщений из 46, показаны все 2 страниц
Форумы / C++ [игнор отключен] [закрыт для гостей] / sizeof( strcuct {string} )?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]