STL容器函数返回值

rub*_*nvb 8 c++ containers stl return-value

在查看STL容器的成员函数时,我发现了一个奇怪的想法.为什么函数std::vector<T>::push_back(T)不具有(可选)返回值(迭代器或甚至对附加对象的引用)?我知道std::string函数inserterase返回迭代器,但这是显而易见的原因.我认为它经常会保存经常跟随这些函数调用的第二行代码.

我敢肯定C++的设计师有很好的理由,请赐教:)

更新:我在这里包含一个真实的代码示例,它可以减少代码长度:

if( m_token != "{" )
{
    m_targets.push_back( unique_ptr<Target>(new Dough(m_token)) );
    return new InnerState( *(m_targets.back()), this );
}
Run Code Online (Sandbox Code Playgroud)

可以减少到

if( m_token != "{" )
    return new InnerState( *(m_targets.push_back( unique_ptr<Target>(new Dough(m_token)) )), this );
Run Code Online (Sandbox Code Playgroud)

如果我假设std::list::push_back返回对添加元素的引用.代码有点重,但由于unique_ptr构造函数和解引用它,这主要是(两组括号).也许为了清晰起见没有任何指针的版本:

if( m_token != "{" )
{
    m_targets.push_back( Dough(m_token) );
    return new InnerState( m_targets.back(), this );
}
Run Code Online (Sandbox Code Playgroud)

if( m_token != "{" )
    return new InnerState( m_targets.push_back( Dough(m_token) ), this );
Run Code Online (Sandbox Code Playgroud)

sme*_*lin 6

无法以安全的方式返回添加的元素或容器成员函数中的容器.STL容器大多提供"强有力的保证".返回操纵元素或容器将使得不可能提供强有力的保证(它只提供"基本保证").这背后的原因是,返回一些东西可能会调用一个拷贝构造函数,这可能会抛出异常.但是这个功能已经退出,所以它成功地完成了它的主要任务,但仍然抛出异常,这违反了强有力的保证.你可能会想:"好吧,然后让我们通过引用返回!"虽然这听起来像是一个很好的解决方案,但它也不是非常安全.考虑以下示例:

MyClass bar = myvector.push_back(functionReturningMyClass()); // imagine push_back returns MyClass&
Run Code Online (Sandbox Code Playgroud)

尽管如此,如果复制赋值运算符抛出,我们也不知道push_back是否成功,从而间接违反了强保证.即使这不是直接违规.当然使用MyClass& bar = //...相反会修复这个问题,但是容器可能会进入一个不确定的状态会非常不方便,因为有人忘记了&.

一个非常类似的推理背后std::stack::pop()是不返回弹出值的事实.而是top()以安全的方式返回最顶层的值.在调用top之后,即使复制构造函数或复制赋值构造函数抛出,您仍然知道堆栈没有改变.

编辑: 我相信为新添加的元素返回一个迭代器应该是完全安全的,如果迭代器类型的复制构造函数提供无抛出保证(我知道的每一个).


小智 5

有趣的问题.显而易见的返回值将是操作发生的向量(或其他),因此您可以编写如下代码:

if ( v.push_back(42).size() > n ) {
   // do something
}
Run Code Online (Sandbox Code Playgroud)

我个人不喜欢这种风格,但我想不出一个不支持它的好理由.