Vai esi kādreiz saskāries ar programmas avāriju, kas liek saķert galvu un domāt, kāpēc šāda elementāra kļūda vispār nonāca līdz lietotājam? C++ programmēšanas valoda nemitīgi attīstās, piedāvājot rīkus, kas palīdz veidot arvien stabilāku un drošāku kodu. Viens no šādiem klusajiem varoņiem, kas var būtiski uzlabot koda kvalitāti, ir mazpazīstamais datu tips std::nullptr_t. Lai gan daudzi zina nullptr kā vērtību, std::nullptr_t kā tips paver jaunas iespējas kļūdu atklāšanai jau kompilēšanas laikā.
Kas ir nullptr un kāpēc tas ir bīstams?
Programmēšanā nullptr tiek izmantots, lai norādītu, ka rādītājs nenorāda uz nevienu derīgu atmiņas apgabalu. Tas ir noderīgs, taču var radīt problēmas, ja to nepareizi apstrādā. Piemēram, mēģinājums izveidot std::string objektu no nullptr ir definīcijas pārkāpums un noved pie nedefinētas uzvedības. Praksē tas nozīmē, ka programma var avarēt vai darboties neparedzami.
Lielākajā daļā standarta bibliotēku šādas situācijas tiek pārbaudītas ar assert paziņojumiem. Lūk, vienkāršots piemērs, kā varētu izskatīties std::string konstruktors:
class string {
// data members
public:
string(const char* str)
{
assert(nullptr != str);
// ...
}
};
Šādas pārbaudes ir noderīgas, taču tās darbojas tikai programmas izpildes (runtime) laikā. Tas nozīmē, ka kļūda var palikt nepamanīta, kamēr konkrētais koda fragments netiek izpildīts.
Kāpēc kompilēšanas laika pārbaudes ir labākas?
Atšķirībā no izpildes laika pārbaudēm (piemēram, assert), kas atrod kļūdas tikai tad, kad programma tiek palaista un attiecīgais koda ceļš tiek izpildīts, kompilēšanas laika pārbaudes atrod kļūdas jau koda apstrādes fāzē. Tas nozīmē, ka kompilators brīdina par potenciālo problēmu, pirms programma vispār tiek salikta un palaista. Šāda pieeja ir daudz efektīvāka, jo ietaupa laiku, kas tiktu tērēts kļūdu meklēšanai un atkļūdošanai, un nodrošina, ka izstrādātā versija jau sākotnēji ir stabilāka.
Ienāk std::nullptr_t glābiņš
Pats std::nullptr_t ir datu tips, kas var saturēt tikai vērtību nullptr. Inovatīvs risinājums, lai novērstu kļūdas jau kompilēšanas laikā, ir pievienot std::string klasei dzēstu konstruktoru, kas pieņem std::nullptr_t tipa argumentu. Tas izskatās šādi:
class string {
// data members
public:
string(const char* str)
{
assert(nullptr != str);
// ...
}
string(std::nullptr_t) = delete("Konstrukcija no nullptr nav atļauta");
};
Šāda konstrukcija tagad paziņos par kļūdu jau kompilēšanas laikā, ja mēģināsiet tieši izveidot std::string no nullptr (piemēram, string berry{nullptr};). Lai gan const char* data{nullptr}; string cherry{data}; gadījumā assert joprojām būs nepieciešams, lai notvertu dinamiskās kļūdas, std::nullptr_t pieeja atrisina vismaz daļu problēmu agrīnā stadijā.
Nākotnes perspektīvas ar C++23 un C++26
C++ valodas standartizācijas komiteja ir atzinusi šī risinājuma nozīmi. Sākot ar C++23, gan std::string, gan std::string_view jau ir ieviesti dzēstie konstruktori no std::nullptr_t, lai automātiski novērstu šīs situācijas kompilēšanas laikā. Turklāt, sākot ar C++26, delete atslēgvārdu varēs papildināt ar pielāgotu ziņojumu, kas sniegs programmētājiem daudz skaidrākus norādījumus par kļūdas iemeslu, vēl vairāk atvieglojot koda atkļūdošanu un uzlabojot koda drošību.
Kopumā std::nullptr_t izmantošana dzēstos konstruktoros ir spēcīgs solis C++ koda drošības uzlabošanā. Tas atļauj kompilatoram paveikt lielāku daļu darba, identificējot un novēršot kļūdas, pirms tās nonāk līdz programmas izpildei. Šādi mazi, bet ietekmīgi uzlabojumi palīdz veidot stabilāku un uzticamāku programmatūru kopumā.
Un kādas C++ funkcijas Tu uzskati par visnoderīgākajām drošāka koda rakstīšanā?
Iezīmē tekstu un spied ziņot par kļūdu.