c++ std::reverse不适用于具有非默认复制指定操作符的对象向量

iszxjhcz  于 2023-01-18  发布在  其他
关注(0)|答案(1)|浏览(135)

在下面的例子中,vec在调用std::reverse之前和之后保持相同的顺序。如果我使Foo.a不是const,并删除复制赋值操作符,那么向量将正确地反转,但我不明白为什么。
在调试时,赋值操作符在std::reverse内部调用时似乎确实正确地复制了对象,所以我不明白应该做些什么不同的事情。

#include <vector>
#include <algorithm>
#include <iostream>

struct Foo
{
    Foo(int a, int b) : a(a), b(b) {}
    Foo operator=(const Foo& other)
    {
        return Foo(other);
    }
    const int a;
    int b;
    Foo doThing()
    {
        Foo copy(*this);
        copy.b++;
        return copy;
    }
};

void print(std::vector<Foo>& vec)
{
    for (const auto& foo : vec)
    {
        std::cout << foo.b << '\n';
    }
}

int main()
{
    Foo initial(-1, 0);
    std::vector<Foo> vec;
    vec.push_back(initial);
    for (size_t i = 0; i < 10; i++)
    {
        vec.push_back(vec[i].doThing());
    }
    std::cout << "before std::reverse \n\n";
    print(vec);
    std::reverse(vec.begin(), vec.end());
    std::cout << "\nafter std::reverse \n\n";
    print(vec);
    std::cout.flush();
}
q0qdq0h2

q0qdq0h21#

这在c20之前是不可能的,因为const成员不能通过赋值w/o UB来改变,这也是为什么const成员在对象中被强烈反对的原因。但是现在是了。但是你仍然需要写一个赋值运算符。为了将来证明代码(c23以上)你还应该包含一个copy ctor,因为隐式的copy ctor可能会被移除。下面是工作代码,不涉及UB:

#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>

struct Foo
{
    Foo(int a, int b) : a(a), b(b) {}
    Foo& operator=(const Foo& other)
    {
        if (this == &other)
            return *this;
        std::destroy_at(this);
        std::construct_at(this, other);
        return *this;
    }
    Foo(const Foo& a) = default;  // Future proof
    const int a;
    int b;
    Foo doThing()
    {
        Foo copy(*this);
        copy.b++;
        return copy;
    }
};

void print(std::vector<Foo>& vec)
{
    for (const auto& foo : vec)
    {
        std::cout << foo.b << '\n';
    }
}

int main()
{
    Foo initial(-1, 0);
    std::vector<Foo> vec;
    vec.push_back(initial);
    for (size_t i = 0; i < 10; i++)
    {
        vec.push_back(vec[i].doThing());
    }
    std::cout << "before std::reverse \n\n";
    print(vec);
    std::reverse(vec.begin(), vec.end());
    std::cout << "\nafter std::reverse \n\n";
    print(vec);
    std::cout.flush();
}

相关问题