Java では、返された要素を実際に返す end の削除メソッドDeque
がクラスにあります。C++ では、同じ動作を実現する唯一の方法は、最初に要素を明示的にコピーしてからポップすることです。
std::deque<int> myDeque;
myDeque.push_back(5);
int element = myDeque.back();
myDeque.pop_back();
両方を同時に行うメカニズムはありますか?
独自のラッパー関数テンプレートを作成できます。
// Precondition: !container.empty()
// Exception safety: If there is an exception during the construction of val,
// the container is not changed.
// If there is an exception during the return of the value,
// the value is lost.
template <typename C>
auto back_popper(C & container) -> decltype(container.back())
{
auto val(std::move(container.back()));
container.pop_back();
return val;
}
使用法:
auto element = back_popper(myDeque);
back()
そもそもandの分離の動機となる根本的な問題を回避することはできません。pop_back()
つまり、要素のコピーまたは移動コンストラクターが例外をスローする可能性があり、これが発生するとポップされた要素が失われる可能性があります。スローしないオブジェクト、たとえば a を返すことでケースバイケースで軽減できますがunique_ptr
、これは動的割り当ての要素を失うリスクと引き換えになりますが、明らかにそれはあなたがしなければならない個人的な選択です。あなたのためにはなりません。
例えば:
// Guarantees that you either get the last element or that the container
// is not changed.
//
template <typename C>
auto expensive_but_lossless_popper(C & container)
-> typename std::unique_ptr<decltype(container.back())>
{
using T = decltype(container.back());
std::unique_ptr<T> p(new T(std::move(container.back())));
container.pop_back();
return p; // noexcept-guaranteed
}
編集: @Simpleが示唆したようstd::move
に、呼び出しを追加しました。back()
これは、moved-from 要素が不要になったため正当であり、多くの実際のクラスには noexcept ムーブ コンストラクターが付属しているため、これで多数のケースがカバーされます。 noexcept の動きがない「奇妙な」タイプ。
設計上、C++ は、例外の安全性を確保するために、すぐに使用できるメカニズムを提供していません。
実装しようとすると、最初に要素のコピーを作成し、次にコンテナーをポップして、最後にオブジェクトを呼び出し元に返します。しかし、最後の操作のコピー コンストラクターが例外をスローするとどうなるでしょうか。オブジェクトはコンテナー内に存在せず、発信者はオブジェクトのコピーを受け取りませんでした。それを防ぎ、コンテナーの操作で強力な例外保証を提供するために、同時にポップされる要素を返す操作は直接サポートされません。