【问题标题】:vector - swap two elements when elements have const membersvector - 当元素具有 const 成员时交换两个元素
【发布时间】:2016-08-31 09:28:07
【问题描述】:

我有以下代码

class a {
public:
    const int aa;
    a(int aa) : aa(aa){}
};
int main() {
    std::vector<a> v;
    v.emplace_back(1);
    v.emplace_back(2);
    v.emplace_back(3);
    v.emplace_back(4);

    std::iter_swap(v.begin() + 1, v.rbegin());

    system("pause");
    return 0;
}

当我尝试交换向量的两个元素时出现错误。

Error   C2280   'a &a::operator =(const a &)': attempting to reference a deleted function

我知道这是因为 a 有一个固定成员,但我不知道如何让它工作。

【问题讨论】:

  • 你根本做不到。
  • 嗯,我可以看到他来自哪里。他想交换对象而不是操纵它们。但是,是的,这不是 C++ 中的意图

标签: c++ c++11 vector constants swap


【解决方案1】:

问题在于swap 改变了现有元素的值。由于元素是 const,因此它们无法更改,因此编译器错误。

如果你坚持使用 const 元素,你的向量应该是 vector&lt;a*&gt; 或事件更好 vector&lt;unique_ptr&lt;a&gt;&gt;。这将允许您在不改变 a 的实际元素的情况下交换元素

【讨论】:

  • 我现在明白为什么我不能做我想做的事了。我的新问题是为什么我不能在v[2] 处破坏a 并将v[3] 移动/复制到那个位置?
  • 一次一个问题
  • 我应该提出一个新问题吗?值得问吗?
  • j2ko 给出了这个答案,它确实有效。 std::swap 调用复制操作符,因此它会执行任何程序。默认是逐个元素复制。
【解决方案2】:

基于this线程以下作品:

#include <vector>
#include <iostream>

class Foo {
public:
    const int value;
    Foo(const int &&from) : value(std::move(from)){}
    Foo(const Foo &&other) : value(std::move(other.value)){}
    Foo & operator=(Foo && source) {
        this -> ~ Foo ();
        new (this) Foo(std::move(source));
        return *this;
    }
};

int main() {
    std::vector<Foo> v;
    v.emplace_back(1);
    v.emplace_back(2);
    v.emplace_back(3);
    v.emplace_back(4);

    std::cout << (v.begin() + 1)->value << "," <<v.rbegin()->value << std::endl;
    std::iter_swap(v.begin() + 1, v.rbegin());
    std::cout << (v.begin() + 1)->value << "," <<v.rbegin()->value << std::endl;
    return 0;
}

【讨论】:

  • 如果 Foo 继承自,或者任何销毁/创建操作可能抛出,则无法从...中恢复。
  • 我并不是说这是一种解决方案,只是另一种选择。
  • 我只是说这是一个疯狂的解决方案。我想不出为什么它并不总是非法的,所以它是 a 解决方案。
  • 这一点也不可怕。 Foo 不能被继承,因为 Foo 是在向量中就地构造的,placement new 只是调用构造函数,所以如果构造函数不抛出,placement new 永远不会抛出。 (正常 new 会分配可能失败的内存)
  • 我花了一段时间才明白,但我想通了。了解新安置特别有趣。谢谢!
【解决方案3】:

这是可能的。由于std::iter_swapstd::vector 迭代器实现如下所示:

using std::swap;
swap(*iter1, *iter2);

你可以定义自己的swap函数:

class A {
    const int aa;
public:
    A(int aa) : aa(aa){}

    void swap(A &other)
    {
        std::swap(const_cast<int &>(aa), const_cast<int &>(other.aa));
    }
};

void inline swap(A &a1, A &a2)
{
    a1.swap(a2);
}

还有works

有关其工作原理的更多信息,例如,请参阅著名的 Scott Meyers 书籍“Effective C++”,规则 25。如果找不到,我可以尝试解释它(我认为 Meyers 先生做得更好)。

@doron 关于指针向量的提示在对象很大时是一个非常好的选择。

编辑

@Yakk 建议将 const 变量转换为非常量变量会导致未定义的行为。 最好不要这样使用。

【讨论】:

  • 从最初声明为 const 的东西中转换 const 是未定义的行为。
  • @Yakk 一般情况下你是对的。应编辑答案。
【解决方案4】:

它也可以在没有 r-value 和 std::move 的情况下工作

const a& operator=(const a &other)
{
    this->~a();
    new (this) a(other.aa);
    return *this;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    相关资源
    最近更新 更多