将结构复制到具有常量值的数组

Copy struct to array with const values

我正在尝试替换非 const 数组中具有 const 值但无法编译的结构值:

Object of type 'Foo' cannot be assigned because its copy assignment operator is implicitly deleted

这是一个例子:

struct Foo {
    const int id;
    int value;
    Foo(): id(-1), value(-1) {}
    Foo(int id): id(id), value(0) {}
};


int main(int argc, const char * argv[]) {
    Foo foos[10];
    foos[0] = Foo(1234);
    return 0;
}

我来自 swift 背景,在该背景下有效,因为它将结构值复制到数组中。

我尝试制作我认为是复制赋值运算符的东西,但对于 const 成员,我尝试的东西也不起作用。

这就是我试图为复制赋值运算符做的事情:

    Foo& operator= (Foo newVal) {
        // what do I put here!?
        return *this;
    };

对数组进行 memcpy 工作但似乎用错了大锤。

作为 c++ 的新手,我不确定这种类型的流程的正确模式是什么。

在C++中,一个对象只能初始化一次。当您声明数组时,您的常量成员通过默认构造函数进行初始化。然后,您尝试通过赋值

更改该值
foos[0] = Foo(1234);

这失败了,这是正确的。你可以做的一件事是拥有一个不是 Foos 的容器,而是某种指向 foo 的指针。因此,您将为指针分配内存,但只会在可以时创建实际对象。例如:

Foo* foos[10]; //here you have only the pointers
foos[0] = new Foo(1234); //OK, the object is inialized here

您可以考虑使用 std::unique_ptr 等智能指针来代替原始指针。

C++ 非常严格地对待 const。如果可能的话,复制这样的结构将是痛苦的(没有 UB)。也许您真正要寻找的是“只读”?在这种情况下,您可以使用 public getters/setters:

将字段设为私有
struct Foo {
    public:
        Foo(): id(-1), value(-1) {}
        Foo(int id): id(id), value(0) {}

        int getId() const {
            return id;
        }

        int getValue() const {
            return value;
        }

        void setValue(int newValue) {
            value = newValue;
        }

    private:
        int id;
        int value;
};

const 值在初始化后永远无法更改。

从名称 id 听来,move 语义正是您所需要的。您可以 移动 对象之间的数据,而不是 复制 ,而不是让两个有效对象具有相同的 id ]它。

示例:

#include <iostream>
#include <utility>

struct Foo {
    Foo() : id(-1), value(-1) {}                      // default - "invalid" values

    Foo(int id, int value) : id(id), value(value) {} // constructor
    explicit Foo(int id) : Foo(id, 0) {}             // converting ctor, delegating 

    Foo(const Foo&) = delete;                        // no copy construction
    Foo(Foo&& rhs) :                                 // move construction ok
        id(std::exchange(rhs.id, -1)),               // take id, give -1 back
        value(std::exchange(rhs.value, -1))          // take value, give -1 back
    {}
    Foo& operator=(const Foo&) = delete;             // no copy assignment
    Foo& operator=(Foo&& rhs) {                      // move assignment ok
        // give the "moved from" element our id and value and
        // take id and value from the "moved from" element
        std::swap(id, rhs.id);
        std::swap(value, rhs.value);
        return *this;
    }

    int Id() const { return id; }        // only const access
    
    int& Value() { return value; }       // non-const access in non-const context
    int Value() const { return value; }  // const access in const context

private:
    int id;
    int value;
};

int main() {
    Foo foos[2];
    foos[0] = Foo(1234);     // The temporary Foo will have (-1, -1) when it's destroyed
    for(auto& f : foos)
        std::cout << f.Id() << ' ' << f.Value() << '\n';
}

输出:

1234 0
-1 -1

时代,C++标准变了!

您现在可以为 类 定义自己的 copy-assignment 运算符,其中包含 const 成员对象,自 c++20 起没有未定义的行为。

这是 c++ 之前的未定义行为,对于完整的 const 对象仍然如此,但 non-const 具有 const 成员的对象则不然。