Pytanie Jak używać nowego typu std :: byte w miejscach, gdzie wymagany jest stary znak unsigned char?


std::byte to nowy typ w C ++ 17, który jest wykonany jako enum class byte : unsigned char. To uniemożliwia korzystanie z niego bez odpowiedniej konwersji. Tak więc stworzyłem alias dla wektora tego typu, który reprezentuje tablicę bajtów:

using Bytes = std::vector<std::byte>;

Jednak nie można go używać w starym stylu: funkcje, które akceptują go jako parametr, nie działają, ponieważ tego typu nie można łatwo przekonwertować na stary std::vector<unsigned char> wpisz, na przykład, użycie zipper biblioteka:

/resourcecache/pakfile.cpp: In member function 'utils::Bytes resourcecache::PakFile::readFile(const string&)':
/resourcecache/pakfile.cpp:48:52: error: no matching function for call to 'zipper::Unzipper::extractEntryToMemory(const string&, utils::Bytes&)'
     unzipper_->extractEntryToMemory(fileName, bytes);
                                                    ^
In file included from /resourcecache/pakfile.hpp:13:0,
                 from /resourcecache/pakfile.cpp:1:
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note: candidate: bool zipper::Unzipper::extractEntryToMemory(const string&, std::vector<unsigned char>&)
     bool extractEntryToMemory(const std::string& name, std::vector<unsigned char>& vec);
          ^~~~~~~~~~~~~~~~~~~~
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note:   no known conversion for argument 2 from 'utils::Bytes {aka std::vector<std::byte>}' to 'std::vector<unsigned char>&'

Próbowałem wykonywać naiwne odlewy, ale to też nie pomaga. A więc, jeśli ma on być użyteczny, czy rzeczywiście będzie użyteczny w starych kontekstach? Jedyną metodą, jaką widzę, jest użycie std::transform do używania nowego wektora bajtów w tych miejscach:

utils::Bytes bytes;
std::vector<unsigned char> rawBytes;
unzipper_->extractEntryToMemory(fileName, rawBytes);
std::transform(rawBytes.cbegin(),
               rawBytes.cend(),
               std::back_inserter(bytes),
               [](const unsigned char c) {
                   return static_cast<std::byte>(c);
               });
return bytes;

Który jest:

  1. Brzydki.
  2. Zajmuje wiele niepotrzebnych linii (można je przepisać, ale wciąż trzeba je napisać wcześniej :)).
  3. Kopiuje pamięć zamiast tylko używać już utworzonego fragmentu rawBytes.

A więc, jak używać go w starych miejscach?


18
2017-09-11 07:54


pochodzenie


Możliwy duplikat: Jak używać czegoś takiego std::basic_istream<std::byte> - Paul R
Nie możesz zmienić swojego parametru funkcji z std::vector<unsigned char>& do std::vector<std::byte>&? - Galik
@Galik to nie moja funkcja ... - Victor Polevoy


Odpowiedzi:


Nie rozumiesz, dlaczego std::byte został wymyślony w pierwszej kolejności. Powodem jego wynalezienia jest przechowywanie w pamięci surowego bajtu bez założenia, że ​​jest to postać. Możesz to zobaczyć w cppreference.

Podobnie jak char i unsigned char, może być używany do uzyskiwania dostępu do surowej pamięci zajmowanej przez inne obiekty (reprezentacja obiektów), ale w przeciwieństwie do tych typów, nie jest typem znaku i nie jest typem arytmetycznym.

Należy pamiętać, że język C ++ jest językiem ściśle napisanym w interesie bezpieczeństwa (dlatego niejawne konwersje są w wielu przypadkach ograniczone). Znaczenie: Jeśli niejawna konwersja z byte do char było możliwe, pokonałoby to cel.

Aby odpowiedzieć na twoje pytanie: Aby go użyć, musisz rzucić go, gdy chcesz wykonać zadanie:

std::byte x = (std::byte)10;
std::byte y = (std::byte)'a';
std::cout << (int)x << std::endl;
std::cout << (char)y << std::endl;

Coś innego nie zadziała, według projektu! Tak więc transformacja jest brzydka, uzgodniona, ale jeśli chcesz przechowywać znaki, użyj char. Nie używaj bajtów, chyba że chcesz przechowywać nieobrobioną pamięć to nie powinno być interpretowane jako char domyślnie.

Ostatnia część pytania jest generalnie niepoprawna: nie musisz wykonywać kopii, ponieważ nie musisz kopiować całego wektora. Jeśli musisz chwilowo przeczytać a byte jak char, po prostu static_cast to w miejscu, w którym musisz go użyć jako char. To nic nie kosztuje i jest bezpieczne dla rodzaju.


Co do twojego pytania w komentarzu do castingu std::vector<char> do std::vector<std::byte>nie możesz tego zrobić. Ale możesz użyć surowej tablicy pod spodem. Tak więc poniższe ma typ (char*):

std::vector<std::byte> bytes;
//fill it...
char* charBytes = static_cast<char*>(&bytes.front()); 

To ma typ char*, który jest wskaźnikiem do pierwszego elementu twojej tablicy i można go dereferencjonować bez kopiowania, jak następuje:

std::cout << charBytes[5] << std::endl; //6th element of the vector as char

I rozmiar, z którego czerpiecie bytes.size(). Jest to ważne, ponieważ std::vector jest ciągłe w pamięci. Zwykle nie można tego zrobić z żadnym innym pojemnikiem std (deque, list, etc ...).

Chociaż jest to ważne, usuwa część bezpieczeństwa z równania, o czym należy pamiętać. Jeśli potrzebujesz char, nie używaj byte.


24
2017-09-11 08:13



Możesz także użyć std::byte{10} zainicjować to. - Simple
(Tylko) inne sąsiadujące std:: pojemnik jest std::array - Caleth
@Caleth i std::string. - Simple
użyłbym static_cast<char*>(bytes.data()) zamiast :) - Rakete1111
@JiaHaoXu Nie sugerowałem tego, ponieważ jest bardzo niebezpieczny i nie jest bezpieczny. Powszechne jest tworzenie specjalizacji szablonów dla typów, co nie gwarantuje takiej samej struktury klasy. O wiele bezpieczniej jest po prostu użyć wewnętrznej tablicy. - The Quantum Physicist


Jeśli chcesz czegoś, co zachowuje się jak bajt w sposób, jakiego prawdopodobnie się spodziewałeś, ale nazywa się wyraźnie inaczej niż bez znaku, użyj uint8_t ze stdint.h. Dla prawie wszystkich wdrożeń będzie to prawdopodobnie

typedef unsigned char uint8_t;

i znowu niepodpisany char pod maską - ale kogo to obchodzi? Po prostu chcesz podkreślić "To nie jest typ postaci". Po prostu nie musisz oczekiwać, że będziesz w stanie mieć dwa przeciążenia niektórych funkcji, jedną dla znaku unsigned char i jedną dla uint8_t. Ale jeśli to zrobisz, kompilator wciśnie na ciebie nos ...


0
2017-07-27 16:28