可以将物体从向量A移动到向量B,但无法从B移动到A?

3
我有一个类,其中包含对象的向量。这些对象已删除复制构造函数和复制赋值运算符,因此它们具有移动构造函数和移动赋值运算符,以允许它们与向量一起使用。这个持有对象的类有附加和提取方法,允许从缓冲区附加对象到类的对象向量中,或从类的对象向量中提取到缓冲区中。
对象定义如下:
struct MyObject
{
    int width_ = 0;
    int height_ = 0;
    //etc...

    stImage() = default; 

    stImage(int width, int height, ...)
    {
        width_ = width;
        height_ = height;
        //etc...
    }

    stImage(const stImage& rhs) = delete;

    stImage& operator= (const stImage & rhs) = delete;

    stImage(stImage&& rhs) : width_(0), height_(0), ...
    {
        *this = std::move(rhs);
    }

    stImage& operator=(stImage&& rhs)
    {
        if (this != &rhs)
        {
            width_ = rhs.width_;
            height_ = rhs.height_;
            //etc...

            rhs.width_ = 0;
            rhs.height_ = 0;
            //etc...
        }
        return *this;
    }
};

追加方法编译:

void MyClass::append(MyObject * buffer)
{
    data_.push_back(std::move(*buffer));
}

void MyClass::append(Vector<MyObject> * buffer)
{
    for (int i = 0; i < (*buffer).size(); i++) 
    {
        data_.push_back(std::move((*buffer)[i]));
    }
 }

然而,提取方法并不包括以下内容:
void MyClass::extract(it8 start, Length length, Vector<MyObject> * buffer) const
{
    for (it8 i = start; i < (start + length); i++) 
    {
        (*buffer).push_back(std::move(data_[i]));
    }
}

给出的错误是“C2280 'MyObject :: MyObject(const MyObject &)': 试图引用已删除的函数”
我看不出这两个操作在功能上有任何区别。如果您能提供关于为什么提取失败而附加没有失败的任何见解,以及使提取工作的方法,将不胜感激。
(注意:这里的向量是std :: vector的自定义实现,因为原因,但据我所知,它们的功能相同。如果这可能是问题,并且std :: vector对于当前的附加/提取是可以的,那么我想看看是否使用它会没问题。)

1
你是在一个const方法中这样做的吗?有趣...如果该方法是const,那么data_所选择的operator[]也应该是const的,不是吗? - WhozCraig
1
extract 是一个常量成员函数,而在常量成员函数中,对于每个成员变量的引用都是 const 的。当你访问 data_[i] 时,返回的数据类型是 const MyObject&。所以,你正在向 vector 中推送一个常量对象,这将调用重载版本 push_back(const T&) - MRB
啊,当然,问题出在使用了“const”。我漏掉了这个。谢谢大家的帮助!@MRB,如果你想把这个作为答案发表,我会接受的——你在这里给出了最详尽的解释。 - ELRG
@AndrewKashpur,我认为你对std::vector的评论不太准确; push_back复制或移动,而我在push_back中使用std::move是直接来自于这个使用push_back的参考 - ELRG
@AndrewKashpur std::vector::push_back 有一个 rval-ref 过载,用于移动语义。它并不总是复制。它只需要正确设置(这个代码片段在提取的情况下没有正确设置)。 - WhozCraig
显示剩余4条评论
2个回答

3

extract是一个常量成员函数,在常量成员函数中,对成员变量的每个引用都是常量。当您访问data_[i]时,返回的数据类型是const MyObject&

std::move只是将其输入强制转换为右值引用,在您的情况下,std::move的返回类型为const MyObject&&,但由于该对象具有const限定符,所以对于push_back选择的重载为push_back(const T&)

您可以使用const_castdata_中移除const,但这不是最好的解决方案。也可以使用mutable关键字,但最好的解决方案是将函数声明为非常量函数,因为它修改了对象的内部状态。


0

常量性,我猜。 “提取”从data_中移除,所以不能是const。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接