Как избежать ненужных хранилищ для возможных неопределенных значений в C++C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Как избежать ненужных хранилищ для возможных неопределенных значений в C++

Сообщение Anonymous »

У меня есть абстракция, в которой байт почти всегда равен 0, но иногда может быть неопределенным. Я хотел бы всегда делать байт 0. Как только я сделаю байт нулевым, я хотел бы передать свою абстракцию многим потокам, которые могли бы проверять байт, избегая при этом гонок данных и необоснованных промахов когерентности кэша. Вот минимальный пример:

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 
#include 

struct String {
std::size_t size;
std::size_t capacity;
char *buf;

template
String(const char (&s)[N]) : size(N - 1), capacity(N), buf(new char[N])
{
memcpy(buf, s, N - 1);
}
String(const String &) = delete;
~String() { delete[] buf; }

const char *c_str() const
{
assert(size < capacity);
if (buf[size] != '\0') [[unlikely]] // UB
buf[size] = '\0';
return buf;
}
};

String greeting("hello world");

int
main()
{
greeting.c_str(); // NUL-terminate string before spawning threads
std::vector greeters;
for (int i = 0; i < 24; ++i)
greeters.emplace_back([] { std::puts(greeting.c_str()); });
}
Моя проблема в том, что buf[size] может иметь неопределенное значение, поэтому вычисление buf[size] != '\0' в c_str() является неопределенным поведением. Я не могу на 100% гарантировать, что последний байт всегда равен \0, потому что мой реальный класс получен из контейнера с очень широким интерфейсом, поэтому я не могу гарантировать, что абсолютно все, что происходит с байтами, оставит последний байт со значением '\0', если я сначала не вызвал c_str().
Первый вопрос для юристов языка: правильно ли я понимаю, что код - UB, и есть ли способ получить то, что я хочу внутри язык?
Если строгий C++ безнадежен, мой код должен работать только с gcc и clang, поэтому мой второй вопрос: могу ли я каким-то образом отмыть указатель через встроенную функцию компилятора. Он должен работать на нескольких архитектурах, но я готов отмывать байт с помощью пустой директивы asm, которая подразумевает помещение значения в байт, хотя на самом деле не содержит никакого кода. Например, будет ли следующее безопасно и работать на большинстве архитектур?

Код: Выделить всё

  const char *c_str() const
{
assert(size < capacity);
asm("" : "=m" (buf[size]));
if (buf[size] != '\0') [[unlikely]] // no longer UB?
buf[size] = '\0';
return buf;
}
Целью здесь будет импортировать семантику реальной машины (а именно, что ячейка памяти всегда имеет значение) в абстрактную машину C++. Сейчас я использую C++23, но будет ли это исправлено [[indeterminate]] в C++26?


Подробнее здесь: https://stackoverflow.com/questions/798 ... alues-in-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»