当前位置: 首页 > 知识库问答 >
问题:

为什么我可以从常量向量中移动元素?

董砚
2023-03-14

下面的代码为什么编译?

#include <vector>
#include <iostream>

struct Foo {
  std::vector<int> bar = {1, 2, 3};
};

int main()
{
    Foo foo1;
    const Foo& foo2 = foo1;
    
    std::vector<int> target;
    
    std::move(foo2.bar.begin(), foo2.bar.end(), std::back_inserter(target));

    return 0;
}

std::move的文档说

执行此操作后,“移动自”范围中的元素仍将包含适当类型的有效值,但不一定与移动前的值相同。

所以这实际上可以改变对象foo2,即使它声明为const。为什么这样做有效?

共有2个答案

楚羽
2023-03-14

用例子来说明Andrey Semashev的答案,考虑一下:

#include <vector>

struct movable
{
    movable() = default;
    
    movable(const movable&) = delete;
    movable& operator=(const movable&) = delete;

    movable(movable&&) = default;
    movable& operator=(movable&&) = default;
};

struct copyable
{
    copyable() = default;
    
    copyable(const copyable&) = default;
    copyable& operator=(const copyable&) = default;

    copyable(copyable&&) = delete;
    copyable& operator=(copyable&&) = delete;
};

int main()
{
    // original example
    const std::vector<int> si;
    std::vector<int> ti;
    
    std::move(si.begin(), si.end(), std::back_inserter(ti)); // OK

    // example 2
    const std::vector<copyable> sc;
    std::vector<copyable> tc;
    
    std::move(sc.begin(), sc.end(), std::back_inserter(tc)); // OK

    // example 3
    const std::vector<movable> sv;
    std::vector<movable> tv;
    
    std::move(sv.begin(), sv.end(), std::back_inserter(tv)); // ERROR - tries to use copy ctor

    return 0;
}

即使copyable没有移动构造函数,示例2编译时没有错误,因为std::move在这里选择了复制构造函数。

另一方面,示例3无法编译,因为可移动的的移动构造函数被否定(更好的词?)通过sv的一致性。你得到的错误是:

error: use of deleted function 'movable::movable(const movable&)'

这里有一个完整的例子。

公西翼
2023-03-14

所以这实际上可以改变对象foo2,即使它声明为const。为什么这样做有效?

如果可以的话,std::move算法可以移动输入元素

对于每个输入元素,它执行*dest=std::move(*from),其中destfrom是输出和输入迭代器。由于from取消对常量对象的引用,std::move(*from)创建一个右值引用const int

如果元素属于具有用户定义的复制和移动构造函数的类类型T,则重载解析必须选择复制构造函数(T(const T

底线是std::move(带迭代器的算法)正在执行移动操作,该操作可能调用移动构造函数或赋值,也可能不调用移动构造函数或赋值。如果调用了move构造函数或赋值,并且该移动对源具有破坏性,那么算法将修改源元素。在其他情况下,它将只执行一个复制。

 类似资料:
  • 问题内容: 我知道ES6尚未标准化,但是目前许多浏览器都支持 JS中的关键字。 规范中写道: 常量的值不能通过重新分配而更改,并且常量也不能重新声明。因此,尽管可以在不初始化的情况下声明常量,但这样做是没有用的。 当我做这样的事情: 我看到一切正常仍和是。 但是,如果这样做,我的常量数组已更改。现在是这样,顺便说一句,我仍然无法用更改它。 我这是一个错误,还是我错过了什么?我在最新的chrome和

  • 这应该很容易,但我一直在撞我的头。 我有数字向量 我有一个数值向量v2。v2始终是v1的子集。 我想从v1中删除v2中的所有元素,但每个v2元素只删除一个(而且完全是一个)v1元素。 所需输出 如果我希望将保留在v1之外。使用很容易。 如果我希望将与v1保持一致。此外,也能起到作用。 如果我希望将与v1保持一致。现在返回。不是我想要的。 当答案输入时,我很可能会用头撞我的键盘,但现在我还没有得到最

  • 问题内容: 考虑一下Java中的以下接口: 和以下类: 为什么类A可以出现并覆盖接口I的最终常量? 自己尝试: 问题答案: 尽管事实上您正在隐藏变量,但是知道可以在java中更改final字段非常有趣,因为您可以在此处阅读: Java 5-“最终”不再是最终的 挪威Machina Networks的Narve Saetre昨天给我发了一封便条,其中提到我们可以将句柄更改为最终数组,这是很遗憾的。我

  • 问题内容: 大家好!我有一个简单的问题。…为什么我可以从main方法中获得一个私有变量?我知道,我在包含类中,但这是主要的。我相信主体不是包含它的类的一部分……那么我不会去找私人成员,但是我可以……为什么?请帮助… thx 问题答案: Main是您的类的一部分,您已经在类中声明了它:) main不是您的对象的一部分,它不会是您从该类创建的对象的任何部分,但它仍然是该类的一部分。这对于任何静态函数都

  • 我试图创建一个图,它将有V个顶点。我正在使用向量的向量来表示图(作为邻接列表)。我的图中的节点是从0到V-1的编号,所以adj向量的索引代表了节点的数量。除非我搞错了,adj[u]代表一个向量,所以我应该可以使用adj[u].push_back(v)将顶点v推入顶点u的邻接列表中。所以在我的例子中,adj[4]应该得到与节点4相邻的顶点所在的向量,而.push_back(1) 这不会发生的。我想这

  • 问题内容: 我创建了以下课程 然后我从类中实例化了一个常量值 问题: 为什么我可以更改变量的内容?这不是常数吗?有人可以帮我解释一下,非常感谢。 问题答案: 正如@Wain所说的–这是由于引用类型的性质造成的。实例是一个常量仅意味着您不能为其分配新的引用–但却没有提及实例本身的实际可变性。 如果将类更改为结构,则将看到行为随 _值_类型的不同,因为更改属性会更改您的实际值-因此,如果它是常量,则无