Const std :: string & 0'ın kabul etmesini engelleyin


97

Bin kelimeye bedel:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        std::cout<<s<<"\n";
        return *this;
    }
};

int main() {
    SayWhat ohNo;
    // ohNo[1]; // Does not compile. Logic prevails.
    ohNo[0]; // you didn't! this compiles.
    return 0;
}

Derleyici, 0 sayısı bir dizeyi kabul eden parantez operatörüne iletilirken şikayet etmiyor. Bunun yerine, yöntem derlemeye girmeden önce derler ve başarısız olur:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

Referans için:

> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)

Tahminimce

Derleyici, std::string(0)aynı soruna neden olan yöntemi (google yukarıdaki hata) girmek için yapıcıyı dolaylı olarak kullanmaktadır .

Soru

Sınıf tarafında bunu düzeltmek için yine de var mı, bu yüzden API kullanıcı bunu hissetmez ve derleme zamanında hata tespit edilir?

Yani, aşırı yük eklemek

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

iyi bir çözüm değil.


2
Derlenmiş kod, ohNo [0] 'da Visual Studio'da "0xC0000005: Access ihlali okuma konumu 0x00000000" ile istisna atma
TruthSeeker

5
operator[]()Bir intargümanı kabul eden özel bir aşırı yükleme bildirin ve bunu tanımlamayın.
Peter

2
@Peter Yine de sahip olduğumdan daha iyi bir bağlayıcı hatası olduğunu unutmayın .
kabanus

5
@kabanus Yukarıdaki senaryoda, derleyici hatası olacaktır, çünkü operatör özeldir ! Bağlayıcı hatası yalnızca sınıf içinde çağrılırsa ...
Aconcagua

5
Hiç C ++ 11 mevcuttur senaryolarda özellikle ilginç @Peter - ve bu do bugün bile var (aslında ben başa sahip bir projede değilim, ben hemen hemen bazı yeni özellikler kaçırıyorum ... ).
Aconcagua

Yanıtlar:


161

Nedeni std::string(0)geçerli, 0boş bir işaretçi sabiti olmasından kaynaklanıyor . Yani 0, bir işaretçi alan string yapıcısıyla eşleşir. Daha sonra kod, bir boş gösterici geçemeyeceği ön koşuldan önce çalışır std::string.

Yalnızca değişmez değer 0bir boş gösterici sabiti olarak yorumlanır, eğer bir çalışma zamanı değeri intolsaydı bu sorun olmazdı (çünkü aşırı yük çözünürlüğü intbunun yerine bir dönüşüm arar ). Gerçek 1bir problem 1de değildir , çünkü bir boş gösterici sabiti değildir.

Derleme zamanı sorunu olduğundan (gerçekte geçersiz değerler) derleme zamanında yakalayabilirsiniz. Bu formun aşırı yüklenmesini ekleyin:

void operator[](std::nullptr_t) = delete;

std::nullptr_ttürüdür nullptr. Ve herhangi bir boş gösterici sabiti ile eşleşir 0, olsun 0ULL, veya nullptr. İşlev silindiğinden, aşırı yük çözünürlüğü sırasında derleme zamanı hatasına neden olur.


Bu bugüne kadar en iyi çözüm, tamamen unuttum ben bir NULL pointer aşırı olabilir.
kabanus

Visual Studio'da, "ohNo [0]" bile boş değer istisnası atıyor. Bu std :: string sınıfına özgü bir uygulama anlamına mı geliyor?
TruthSeeker

@pmp Atılan (herhangi bir şey varsa) uygulamaya özgüdür, ancak nokta dize hepsinde bir NULL işaretçisi olmasıdır. Bu çözüm ile istisna kısmına gelmeyeceksiniz, derleme zamanında tespit edilecektir.
kabanus

18
@pmp - Boş bir işaretçiyi yapıcısına geçirmeye std::stringC ++ standardı tarafından izin verilmez. Bu tanımsız bir davranış, bu nedenle MSVC istediği her şeyi yapabilir (istisna atmak gibi).
StoryTeller - Unslander Monica

26

Bir seçenek, integral argümanını kabul eden bir privateaşırı yük bildirmek operator[]()ve bunu tanımlamamaktır.

Bu seçenek, void operator[](std::nullptr_t) = deleteC ++ 11 için geçerli olan seçeneklerin aksine, tüm C ++ standartlarıyla (1998 tarihinde) çalışır .

operator[]()Bir privateüye yapmak, ohNo[0]bu ifade bir üye işlevi veya friendsınıf tarafından kullanılmadığı sürece, örneğinizde teşhis edilebilir bir hataya neden olur .

Bu ifade bir üye işlevden veya friendsınıftan kullanılırsa, kod derlenir, ancak işlev tanımlanmadığı için genellikle yapı başarısız olur (örneğin, tanımlanmamış bir işlev nedeniyle bir bağlayıcı hatası).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.