【问题标题】:Resize on std::vector does not call move constructor [duplicate]在 std::vector 上调整大小不会调用移动构造函数 [重复]
【发布时间】:2015-01-27 08:23:31
【问题描述】:

我一直在玩 std::vector 以了解何时构造、销毁、复制构造和移动构造对象。为此,我编写了以下程序

#include <iostream>
#include <vector>

class Test {
public:
    Test() {
        std::cout << "Constructor called for " << this << std::endl;
    }
    Test(const Test& x) {
        std::cout << "Copy Constructor called for " << this << std::endl;
    }
    Test(Test&& x) {
        std::cout << "Move Constructor called for " << this << std::endl;
    }
    ~Test() {
        std::cout << "Destructor called for " << this << std::endl;
    }
};

int main() {
    std::vector<Test> a( 1 );
    a.resize(3);

    return 0;
}

当调整 a 的大小时,会发生重新分配。我的猜测是对象 a[0] 被移动构造到新的 a[0]。但是,对于 libc++ 和 libstdc++,似乎调用的是复制构造函数而不是移动构造函数。这种行为有什么原因吗?

【问题讨论】:

    标签: c++ c++11 vector move


    【解决方案1】:

    我刚刚找到了问题的答案。必须将移动构造函数声明为 noexcept 才能这样做。完成此类更改后

    Test(Test&& x) noexcept {
        std::cout << "Move Constructor called for " << this << std::endl;
    }
    

    调用移动构造函数。

    【讨论】:

    • 你会认为优化器应该推断出你的构造函数不会抛出和使用它,即使没有 noexcept 说明符。
    • @gbjbaanb 编译器是否曾经推断出修饰符?它不适用于const(作为后缀)。
    • @gbjbaanb 我认为从技术上讲你可以通过ios::exceptionscout 抛出。
    • @gbjbaanb:优化器不应该改变代码的含义。推导noexcept 会是不错的功能,但标准不包含它。
    • 我在查找规范时确实在某处读过它。啊in Pubby's answer。有趣的是,编译器生成的移动构造函数显然没有 noexcept 。像这样的时代,我认为 C++ 已经进入“过于复杂”的领域,正如它的批评者所声称的那样。 :-(
    【解决方案2】:

    正如@InsideLoop 的回答所说,移动构造函数必须声明为“noexcept”才能被调用。

    这是因为在vector::resize()函数调用栈中,我们可以发现move_if_noexcept()在函数__construct_backward()中被调用。(见[你的库路径]/include/c++/v1/memory line:1531)

    construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1));
    

    根据 C++11 标准,我们知道移动构造函数通常用于临时右值。所以move构造函数抛出异常是一件很危险的事情,我们可以为move构造函数声明“noexcept”来避免它。

    使用move_if_noexcept(),虽然会损失性能,但可以使进程安全。当移动构造函数声明为“noexcept”时,该函数将激活移动构造函数。

    (对不起我的英语不好。)

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 2020-10-11
      • 2018-03-12
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      相关资源
      最近更新 更多