2016-01-27 12 views
10

Wszystkie GCC 4.8.4, 4.9.3, 5.3.0 przejść testy dla std::exception (dla każdego z -std = C++ 11/1r/14/1Z/17 warianty, gdzie jest dostępna):Czy konstruktor kopiowania i kopia przypisania std :: runtime_error noexcept?

static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "test exception"); 
static_assert(std::is_nothrow_copy_assignable <std::exception>::value, "test exception"); 

Który jest w porządku, ponieważ std::exception został noexcept specjalne członków (C++ 14 18.8.1):

namespace std { 
    class exception { 
    public: 
    exception() noexcept; 
    exception(const exception&) noexcept; 
    exception& operator=(const exception&) noexcept; 
    virtual ~exception(); 
    virtual const char* what() const noexcept; 
    }; 
} 

Niestety, wszystkie kompilatory powyżej nie na następujących static_assert S:

static_assert(std::is_nothrow_copy_constructible<std::runtime_error>::value, "test runtime_error"); 
static_assert(std::is_nothrow_copy_assignable <std::runtime_error>::value, "test runtime_error"); 

Norma zawiera jedynie następujące informacje std::runtime_error w 19.2.6:

namespace std { 
    class runtime_error : public exception { 
    public: 
    explicit runtime_error(const string& what_arg); 
    explicit runtime_error(const char* what_arg); 
    }; 
} 

Ale nic nie mówi się o noexcept Ness drugiej (niejawnie oświadczył specjalny) członków, ani realizacji pamięci wymagania what_arg.

Standard (C++ 14) mówi o następujących 15,4/14:

konstruktora dziedziczenia (12.9) i pośrednio uznane szczególną funkcyjny element (punkt 12) mają wyjątku specyfikacją. Jeśli f jest dziedziczącym konstruktorem lub domyślnie domyślnym konstruktorem , kopiującym konstruktorem, konstruktorem ruchu, destruktorem, kopiującym operatorem przypisania lub przeniesionym operatorem przypisania, jego domyślna specyfikacja wyjątku określa identyfikator typu T, jeśli i tylko jeśli T jest dozwolone przez specyfikację wyjątków funkcji bezpośrednio wywoływanej przez niejawną definicję f; f zezwala na wszystkie wyjątki, jeśli jakakolwiek funkcja, którą to wywołuje, zezwala na wszystkie wyjątki, a f ma wyjątek-specyfikację wyjątku (true), jeśli każda funkcja wywoływana bezpośrednio przez użytkownika nie dopuszcza żadnych wyjątków.

A idąc 18.8.1/2:

Każde standardowe biblioteki klas T, która wywodzi się z klasy wyjątku powinien mają publicznie dostępny konstruktor kopiujący a publicznie dostępnego operatora przypisania kopiowaniem zrobienia nie wyjdzie z wyjątkiem .

Od std::runtime_error nie wystawiać na realizację przechowywania what_arg, nie wiemy, czy to (specjalne) członkowie są noexcept czy nie, więc noexceptness z std::runtime_error „s kopia konstruktora lub skopiować członkowie przypisania są nierozstrzygalne. Nasz jedyny zakład to 18.8.1 powyżej.

Pytanie 1/a) Uważamy, że konstruktor kopiowania lub przypisanie kopii nie stanowią wyjątku (1, 2). Czy to prawda/state-of-the-art/najlepsza praktyka?

Pytanie 1/b) Czy nie musimy tego wyraźnie podawać w standardzie? (Jak w 18.8.2, klasa bad_exception)

Pytanie 1/c) Czy jest to błąd w GCC, który nie spełnia powyższych testów static_assert?

Pytanie 2) Jeśli powyższe odliczenie jest błędne, czy ktoś mógłby wskazać mi sekcję (y) w standardzie, która stwierdza, że ​​std :: runtime_error nie ma konstruktora kopiowania noexcept (i kopiowania przypisania)? (Lub gdzie stwierdza się, że nie są.)

+0

Czy na pewno gcc 5.3.0 nie zalicza testów dla 'std :: runtime_error'? Wygląda na to, że [gcc 5.2.0 przechodzi testy] (http://melpon.org/wandbox/permlink/aHDNg8cs7ttnJlaW). – cpplearner

+0

Próbowałem z g ++ - 5 (Ubuntu 5.3.0-3ubuntu1 ~ 14.04) 5.3.0 20151204 i nie udało się. –

+0

Hmmmm, mogą wystąpić pewne problemy z moją instalacją GCC 5.3.0, ponieważ ma ona następujące znaczenie w /usr/include/c++/5.3.0/stdexcept: #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS runtime_error (const runtime_error &) _GLIBCXX_ssss_USE_NOEXCEPT; runtime_error & operator = (const runtime_error &) _GLIBCXX_USE_NOEXCEPT; #endif ale nie wyemitowano błędu (zauważ, że zmodyfikowałem definicję _GLIBCXX_) –

Odpowiedz

2

Rozważmy LWG 1371:

Żaden z rodzajów wyjątków określonych w punkcie 19 mogą wyjątek na kopiowanie lub przenoszenie operacji, ale nie jest jasne, specyfikacja, że ​​operacje mają specyfikację wyjątku, aby to udowodnić. Zauważ, że domyślnie zadeklarowani konstruktorzy, pobierający specyfikację wyjątku od swojej klasy bazowej (ostatecznie std::exception) domyślnie wygenerują specyfikację wyjątków noexcept, jeśli wszyscy ich członkowie danych podobnie zadeklarują operacje noexcept. Ponieważ reprezentacja jest nieokreślona, ​​nie możemy zakładać operacji niezwężających się, chyba że jednoznacznie stwierdzimy, że jest to ograniczenie w implementacji.

[Rozdzielczość proponowany przez wyborczej komentarzu:]

Dodaj globalną gwarancję, że wszystkie rodzaje wyjątków określonych w punkcie 19 które opierają się na domyśle zadeklarowane operacje mają zakaz rzucania specyfikacji wyjątków w tych operacjach.

W Batavia spotkania 2010 stwierdzono, że [exception]/2 „pokryta to”:

Każde standardowe biblioteki klas T, która wywodzi się z klasy exception mają publicznie dostępny konstruktor kopiujący i publicznie dostępną kopię operator przypisania, który nie wychodzi z wyjątkiem.

Dlatego nadal nie jest wymagane, aby te specjalne funkcje należały do ​​noexcept. I zgodnie ze sposobem, w jaki niejawne specyfikacje wyjątków są określone w [except.spec]/16, ponieważ implementacja może dodać oba parametry z domyślnymi argumentami i elementami, jest to zależne od implementacji, niezależnie od tego, czy te specjalne funkcje składowe to noexcept.


Powiązane problemy