vs, std::vector, 插入其它位置与插入end,扩展空间的方法不一样, 你们其它开发工具是一样的吗?

GKatHere 2021-04-15 05:10:47
如题,
在VS中,当你在end之前插入时,vector扩展空间使用的是 移动构造函数;
而当在end插入时,vector扩展空间使用的是 copy构造函数;
本身我有一个类只允许移动构造或复制,不允许copy构造或复制........然后使用vector容器的时候,就当掉了



void F() {
struct A {
int v;
A() { printf(CODEPOS_ "A()\n"); }
~A() { printf(CODEPOS_ "\n"); }
A(const A&) { printf(CODEPOS_ "A(const A&)\n"); };
A(A&&r) { printf(CODEPOS_ "A(A&&r)\n"); r.v = 0; };
A& operator=(A&&r) { printf(CODEPOS_ "A& operator=(A&&r)\n"); r.v = 0; return *this; };
A& operator=(const A&) { printf(CODEPOS_ "A& operator=(const A&)\n");; return *this; };
};
std::vector<A> a(1);
A b;
// vector 插入其它位置与插入end,扩展空间的方法不一样
// 插入其它位置: 调用_Uninitialized_move, 调用移动构造函数
// 插入end: 调用_Uninitialized_copy, 调用copy构造函数
/*
vs <vector>相关源码:
template<class... _Valty>
pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val)
{ // reallocate and insert by perfectly forwarding _Val at _Whereptr
...
if (_Whereptr == this->_Mylast()) // 插入end: 调用_Uninitialized_copy, 调用copy构造函数
{ // at back, provide strong guarantee
_Umove_if_noexcept(this->_Myfirst(), this->_Mylast(), _Newvec);
}
else // 插入其它位置: 调用_Uninitialized_move, 调用移动构造函数
{ // provide basic guarantee
_Umove(this->_Myfirst(), _Whereptr, _Newvec);
_Constructed_first = _Newvec;
_Umove(_Whereptr, this->_Mylast(), _Newvec + _Whereoff + 1);
}
...
}
*/
a.insert(a.begin(), std::move(b)); // 调用移动构造函数 扩展空间
a.insert(a.end(), std::move(b)); // 调用copy构造函数 扩展空间

}
...全文
136 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
GKatHere 2021-04-16
  • 打赏
  • 举报
回复
vs 不加noexcept也编译过了... 楼上两位看看我在debug下的输出
GKatHere 2021-04-16
  • 打赏
  • 举报
回复
谢了,仔细看了下,确实如此.
coo135 2021-04-16
  • 打赏
  • 举报
回复
你得给移动构造函数加上noexcept 才会被调用啊~~~

        ...
        if (_Whereptr == this->_Mylast())    //        插入end: 调用_Uninitialized_copy,        调用copy构造函数
            {    // at back, provide strong guarantee
            _Umove_if_noexcept(this->_Myfirst(), this->_Mylast(), _Newvec);
            }
        else                                //        插入其它位置: 调用_Uninitialized_move,    调用移动构造函数
            {    // provide basic guarantee
            _Umove(this->_Myfirst(), _Whereptr, _Newvec);
            _Constructed_first = _Newvec;
            _Umove(_Whereptr, this->_Mylast(), _Newvec + _Whereoff + 1);
            }
        ...
如原始注释,vector在末尾插入时(比如:push_back、emplace_back )提供强异常保证;其它位置则提供基本异常保证。 强异常保证期望被调用函数不抛出异常,而这个对象的移动构造函数可以抛出异常,所以就不会被调用了。这函数名一看就懂啊:_Umove_if_noexcept _Umove_if_noexcept源码显示,当移动构造函数不抛异常时,调用移动构造,否则调用copy构造:

    void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, true_type) {
        // move [_First, _Last) to raw _Dest, using allocator
        _Uninitialized_move(_First, _Last, _Dest, _Getal());
    }

    void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, false_type) {
        // copy [_First, _Last) to raw _Dest, using allocator
        _Uninitialized_copy(_First, _Last, _Dest, _Getal());
    }

    void _Umove_if_noexcept(pointer _First, pointer _Last, pointer _Dest) {
        // move_if_noexcept [_First, _Last) to raw _Dest, using allocator
        _Umove_if_noexcept1(_First, _Last, _Dest,
            bool_constant<disjunction_v<is_nothrow_move_constructible<_Ty>, negation<is_copy_constructible<_Ty>>>>{});
    }
flying_music 2021-04-15
  • 打赏
  • 举报
回复
我在GCC4.8.5上试了下,跟插入位置没关系,打印完全一样的 而且楼说的也对,不加noexcept 标准库是不会调用的,加了才会调用
coo135 2021-04-15
  • 打赏
  • 举报
回复
移动构造函数通常期望不抛异常,你这个要抛异常的移动构造函数标准库的容器都不会用的。 你得加上异常说明:noexcept ,保证不抛异常~~ A(A&&r) noexcept { printf(CODEPOS_ "A(A&&r)\n"); r.v = 0; };

64,682

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧