2 votes

try/catch autour de l'affectation des références

Je voudrais attraper une exception d'une méthode qui renvoie une référence, sans attraper la même exception d'un appel ultérieur qui utilise la référence. Par exemple :

try {
    Something &o = myMap.at(myIndex);
    foo(o);
} catch(std::out_of_range &e) {
    // If this was thrown by myMap.at, we can handle it
    // If this was thrown by foo, we can't, and need to propagate it
}

Je cherche donc à faire quelque chose comme ça :

Something &o;
try {
    o = myMap.at(myIndex);
} catch(std::out_of_range &e) {
    // Handle the error
}
foo(o);

Mais bien sûr, ce n'est pas valable. Je peux penser à des façons d'envelopper foo dans une autre exception, puis de la déballer en dehors de l'exception try mais c'est plutôt désordonné. Existe-t-il un meilleur moyen ?

MCVE peut être trouvé ici : https://ideone.com/DJHxpO

6voto

chris Points 28950

Vous pouvez utiliser une expression lambda immédiatement invoquée :

Something &o = [&]() -> decltype(auto) {
    try {
        return myMap.at(myIndex);
    } catch(std::out_of_range &e) {
        // Handle the error
        // Return some other object for o to refer to.
    }
}();
foo(o);

1voto

songyuanyao Points 2265

Vous pouvez utiliser le pointeur à la place :

Something *o; // initialize it with nullptr if necessary
try {
    o = &myMap.at(myIndex);
} catch(std::out_of_range &e) {
    // Handle the error
}
foo(*o);      // check whether it's nullptr before dereference if necessary

1voto

Peter Points 4026

Une méthode simple, qui fonctionne avec toutes les versions de C++, serait la suivante

bool mapped = false;
try {
    Something &o = myMap.at(myIndex);
    mapped = true;
    foo(o);
} catch(std::out_of_range &e) {
     if (mapped) throw;
     //   if we get to here, the exception was thrown by myMap.at()
}

Cela évite également de devoir faire en sorte que la référence fasse référence à un autre objet si myMap.at() échoue.

0voto

Richard Hodges Points 1972

Je pense que c'est un bon cas d'utilisation pour boost::optional (std: : en c++17).

Vous n'avez pas vraiment envie de générer ou de traiter une exception, car le fait que l'élément ne figure pas sur la carte ne constitue pas une circonstance exceptionnelle.

Je pense que je l'exprimerais comme ça :

int myIndex = 1;
foo(maybe_at(myMap, myIndex).value_or_eval([]()->Something& {
    // perform error code here
    return default_something;
}));

Exemple de code complet ici :

#include <map>
#include <type_traits>
#include <boost/optional.hpp>

template<class Container>
struct container_traits
{
    using maybe_const_type = std::remove_reference_t<Container>;
    using container_type = std::decay_t<Container>;
    using is_const = std::is_const<maybe_const_type>;
    using key_type = typename container_type::key_type;
    using raw_mapped_type = typename container_type::mapped_type;
    using mapped_type = std::conditional_t<is_const::value, std::add_const_t<raw_mapped_type>, raw_mapped_type>;
    using mapped_reference = std::add_lvalue_reference_t<mapped_type >;
};

template<class Container, class Key>
auto maybe_at(Container&& container, Key&& key)
{
    using traits = container_traits<Container>;
    using result_type = boost::optional<typename traits::mapped_reference>;

    auto result = result_type {};
    auto ifind = container.find(key);
    if (ifind != container.end()) {
        result = ifind->second;
    }
    return result;
}

struct Something {};

void foo(Something&) {}
void foo(const Something&) {}

std::map<int, Something> myMap1;
const std::map<int, Something> myMap2;

auto default_something = Something{};

int main() {

    int myIndex = 1;

    foo(maybe_at(myMap1, myIndex).value_or_eval([]()->Something& {
        // perform error code here
        return default_something;
    }));

    foo(maybe_at(myMap2, myIndex).value_or_eval([]()->Something const& {
        // perform error code here
        return default_something;
    }));

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X