Open source modální textový editor Helix, inspirovaný editory Vim, Neovim či Kakoune, byl vydán ve verzi 25.07. Přehled novinek se záznamy terminálových sezení v asciinema v oznámení na webu. Detailně v CHANGELOGu na GitHubu.
Americký výrobce čipů Nvidia získal od vlády prezidenta Donalda Trumpa souhlas s prodejem svých pokročilých počítačových čipů používaných k vývoji umělé inteligence (AI) H20 do Číny. Prodej těchto čipů speciálně upravených pro čínský trh by tak mohl být brzy obnoven, uvedla firma na svém blogu. Americká vláda zakázala prodej v dubnu, v době eskalace obchodního sporu mezi oběma zeměmi. Tehdy to zdůvodnila obavami, že by čipy mohla využívat čínská armáda.
3D software Blender byl vydán ve verzi 4.5 s prodlouženou podporou. Podrobnosti v poznámkách k vydání. Videopředstavení na YouTube.
Open source webový aplikační framework Django slaví 20. narozeniny.
V Brestu dnes začala konference vývojářů a uživatelů linuxové distribuce Debian DebConf25. Na programu je řada zajímavých přednášek. Sledovat je lze online.
Před 30 lety, tj. 14. července 1995, se začala používat přípona .mp3 pro soubory s hudbou komprimovanou pomocí MPEG-2 Audio Layer 3.
Výroba 8bitových domácích počítačů Commodore 64 byla ukončena v dubnu 1994. Po více než 30 letech byl představen nový oficiální Commodore 64 Ultimate (YouTube). S deskou postavenou na FPGA. Ve 3 edicích v ceně od 299 dolarů a plánovaným dodáním v říjnu a listopadu letošního roku.
Společnost Hugging Face ve spolupráci se společností Pollen Robotics představila open source robota Reachy Mini (YouTube). Předobjednat lze lite verzi za 299 dolarů a wireless verzi s Raspberry Pi 5 za 449 dolarů.
Dnes v 17:30 bude oficiálně vydána open source počítačová hra DOGWALK vytvořena v 3D softwaru Blender a herním enginu Godot. Release party proběhne na YouTube od 17:00.
McDonald's se spojil se společností Paradox a pracovníky nabírá také pomocí AI řešení s virtuální asistentkou Olivii běžící na webu McHire. Ian Carroll a Sam Curry se na toto AI řešení blíže podívali a opravdu je překvapilo, že se mohli přihlásit pomocí jména 123456 a hesla 123456 a získat přístup k údajům o 64 milionech uchazečů o práci.
namespace { template<typename CharType = wchar_t> std::basic_istream<CharType>& operator>>(std::basic_istream<CharType>& inputStream, std::basic_string<CharType>& line) { std::getline(inputStream, line); return inputStream; } } template<typename CharType = char> auto ReadLines(std::wstring path) { auto inputStream = new std::ifstream(path); using iterator = std::istream_iterator<std::basic_string<CharType>>; auto begin = std::shared_ptr<iterator>( new iterator(*inputStream), [inputStream](auto* iterator) { delete iterator; delete inputStream; } ); return begin; }Je toto správne riešenie? Alebo na to idem zle? Lebo fungovať mi to funguje. Ak viete o niečom priamočiarejšom tak sem s tým. Ďakujem.
auto begin = ReadLines(L"c:\test\newFile21.txt"); for (auto it = *begin; it != std::istream_iterator<std::string>(); ++it) { std::cout << ":" << *it << "n"; }
#include <fstream> #include <iostream> #include <stdexcept> template <typename T> void read_lines(const std::string &path, T &&handler) { std::ifstream s{}; s.open(path); if (!s.is_open()) throw std::runtime_error{"Cannot open file"}; std::string str{}; while (std::getline(s, str).good()) handler(str); } int main() { try { read_lines("abc.txt", [](const std::string &s) { std::cout << s << std::endl; }); } catch (const std::runtime_error &ex) { std::cout << ex.what() << std::endl; } return 0; }
Začal bych od jednoduchého příkladu — implicitní iterace po slovech. To se zařídí třeba takhle:
#include <fstream> #include <iostream> #include <iterator> #include <string> namespace { template<typename C> struct ifstream_iterable { ifstream_iterable(const std::string &path) : stream_{path} {} auto begin() { return iterator{stream_}; } auto end() { return iterator{}; } private: typedef std::istream_iterator<std::basic_string<C>, C> iterator; std::basic_ifstream<C> stream_; }; } // namespace int main() { for (auto &w : ifstream_iterable<wchar_t>{"/proc/cpuinfo"}) std::wcout << w << std::endl; }
To bychom měli. Teď je otázka, jak z toho^^^ udělat iteraci po řádcích. Předně pár poznámek k tématu:
>>
je mírně špatně v mezích zákona, protože deklarace je hodně podobná této deklaraci v headeru <string>
, což sice na první pohled nevadí, ale na druhý pohled tam hraje roli až příliš mnoho složitých detailů kolem pravidel pro hledání identifikátorů. Drobná změna standardu a/nebo (kni)hovny může vést k tomu, že operátor se buď vůbec nepoužije, nebo začne být v konfliktu s operátory z (kni)hovny. Drobnou modifikací se mi podařilo vyrobit (proti)příklad, kdy clang++
i g++
kód přeloží bez varování, ale g++
„přetížený“ operátor použije, zatímco clang++
nikoliv.std::string
(což je sice technicky možné, ale z hlediska kompatibility a udržovatelnosti kódu je vhodné se takových nápadů vyvarovat)Co tedy podniknout? Třeba tohle:
#include <fstream> #include <iostream> #include <iterator> #include <string> #include <utility> namespace { template <typename C> struct line { std::basic_istream<C>& operator <<(std::basic_istream<C> &stream) { std::getline(stream, str_); return stream; } operator const std::basic_string<C>&() const & { return str_; } operator std::basic_string<C>&() & { return str_; } // zde se nepoužije operator std::basic_string<C>() && { return std::move(str_); } // -dtto- private: std::basic_string<C> str_; }; template <typename C> std::basic_istream<C>& operator >>(std::basic_istream<C> &stream, line<C> &str) { str << stream; return stream; } template<typename C> struct ifstream_iterable { ifstream_iterable(const std::string &path) : stream_{path} {} auto begin() { return iterator{stream_}; } auto end() { return iterator{}; } private: typedef std::istream_iterator<line<C>, C> iterator; std::basic_ifstream<C> stream_; }; } // namespace int main() { for (const std::wstring &l : ifstream_iterable<wchar_t>{"/proc/cpuinfo"}) std::wcout << l << std::endl; }
Tohle^^^ nedědí od základních typů, nevyvolává příliš mnoho nespecifikovaných rohových případů, nepoužívá kámoše a vystačí si s jednou třídou (dělnickou), kterou lze konvertovat na odpovídající string
. (Pro složitější konverze do jiného API si lze napsat deduction guides, ale to už je jiné téma. V této podobě se kód přeloží s C++ 14, 17 i 20, zatímco s deduction guides by vyžadoval minimálně C++17.)
Ještě závěrem dodám (a předejdu tak, doufám, některým komentářům), že někteří lidé mají utkvělou špatnou představu o sousloví return std::move(...);
— myslí si, že něco takového nedává smysl a že by to nemělo existovat. Samozřejmě se mýlí, jak jinak; tady jsou k tomu předdrobnosti i podrobnosti.
A když nad tím znova přemýšlím (což rozhodně nedělám často), čitelnější to bude bez toho nestandardního operátoru <<
, který nijak neinteraguje s (kni)hovnou a jenom všeho všudy mate čtenáře (včetně mě). Takže raději třeba takto:
#include <fstream> #include <iostream> #include <iterator> #include <string> #include <utility> namespace { template <typename C> struct line { operator const std::basic_string<C>&() const & { return str_; } operator std::basic_string<C>&() & { return str_; } operator std::basic_string<C>() && { return std::move(str_); } // nepoužito private: std::basic_string<C> str_; }; template <typename C> std::basic_istream<C>& operator >>(std::basic_istream<C> &stream, line<C> &str) { std::getline(stream, static_cast<std::basic_string<C>&>(str)); return stream; } template<typename C> struct ifstream_iterable { ifstream_iterable(const std::string &path) : stream_{path} {} auto begin() { return iterator{stream_}; } auto end() { return iterator{}; } private: typedef std::istream_iterator<line<C>, C> iterator; std::basic_ifstream<C> stream_; }; } // namespace int main() { for (const std::wstring &l : ifstream_iterable<wchar_t>{"/proc/cpuinfo"}) std::wcout << l << std::endl; }
Ale ak pri smartpointeroch používate deleter tak sa použitiu delete nevyhnete.
To je sice pravda, ale právě nadužívání dynamické alokace je u C++ poměrně častá chyba. Zrovna třeba statement delete iterator;
není dobrý nápad (a kdekoho přiměje zvednout obočí), protože iterátor má být (a většinou je) malý kousek dat (něco jako 16 B, dejme tomu), který se dá a má předávat všude hodnotou. (Samozřejmě kromě případu, kdy je potřeba z více míst měnit jeden iterátor, tj. mít něco jako dvouhvězdičkový pointer.)
Ještě bych poznamenal, jen tak pro úplnost, že příklad v dotazu by byl lepší s použitím std::unique_ptr
místo std::shared_ptr
. Zatímco std::unique_ptr
je jednoduchý zapouzdřený pointer, který vyjadřuje exkluzivní vlastnictví a vlastní z jednoho kontextu jeden kousek dat, std::shared_ptr
je složitá mašinerie s atomickým reference-countingem. Uvnitř v implementaci std::shared_ptr
neukazuje přímo na data, která spravuje, nýbrž na svou vlastní dynamickou strukturu, ve které má (kromě pointeru) také atomické počítadlo referencí a pár dalších vychytávek. (Dlužno navíc dodat, v souvislosti s atomickým počítadlem, že jedna atomická instrukce může stát čas srovnatelný s řádově tisícem sčítání.) Dá se říct, že std::shared_ptr
je v jistém smyslu thread-safe, byť s omezeními:
std::shared_ptr
, každou z jiného vlákna, lze používat paralelně zcela bez omezení.std::shared_ptr
několika vlákny (například rozumně atomické přiřazení toho sdíleného pointeru) ovšem samo od sebe atomické není; k tomu slouží specializace std::atomic<std::shared_ptr<...>>
.Zkrátka a dobře (nebo zdlouha a špatně, teď nevím),
std::unique_ptr
místo std::shared_ptr
, je to jasná volba, zejména z hlediska efektivity a jednoznačnosti vlastnictví objektů. Atomický reference-counting je potřebný jenom velmi zřídka, nikoliv zhusta.
Tiskni
Sdílej: