首页 > 解决方案 > 你应该如何初始化一个我不知道其内容的 Array 属性?

问题描述

我的代码中指定了以下类。

class Foo{

private: 

int myInt;
Bar myList[10];

public:

Foo(){

myInt = 0;

}

void addBar(Bar b){

this->myList[myInt] = b;
myInt ++;
}

};

我收到错误

Foo 的构造函数必须显式初始化没有默认构造函数的成员 myList。

问题是直到运行时我才知道该列表将包含什么,因为用户将Bar对象添加到列表中 - 而我的Bar对象没有默认值,需要指定它们。

我应该如何在那里初始化该变量?

这是类的定义Bar


class Bar{

private:

std::string name;
int number;

public:

Bar(std::string name, int number){
name = name;
number = number;

};

这就是我正在做的main()


int main(){

Bar b("Red",1);
Foo f();

f.addBar(b)

return 0;
}

标签: c++arrays

解决方案


好吧,我建议只使用 astd::vector<Bar>而不是尝试使用原始数组。关于数组的事情是你不能离开它的任何对象未构造。如果你真的想知道如何自己实现它,你首先在数组中使用不同的类型,不需要任何初始化,然后根据需要重用该内存来创建和销毁对象。

“不同类型”是std::aligned_storage_t. 方便的是,页面上的示例正是我们想要的。

// template<class T, std::size_t N>
// class static_vector
// T = Bar; N = 10
class Foo {
    // properly aligned uninitialized storage for 10 Bars
    std::aligned_storage_t<sizeof(Bar), alignof(Bar)> data[10];
    std::size_t size = 0;
public:
    // compiler-provided default constructor does not initialize data
    Foo() = default;

    void addBar(Bar b) {
        if(size >= 10) throw std::bad_alloc{}; // possible error handling
        // reuse uninitialized memory for a Bar
        new(&data[size]) Bar(std::move(b));
        size++; // if constructor can throw, this must be after the constructor!
    }
    Bar const &operator[](std::size_t pos) const noexcept {
        return *std::launder(reinterpret_cast<Bar const*>(&data[pos]));
    }
    Bar &operator[](std::size_t pos) noexcept {
        return *std::launder(reinterpret_cast<Bar*>(&data[pos]));
    }
    void popBar() {
        if(size <= 0) return; // or whatever
        operator[](--size).~Bar();
    }

    // Have to remember to clean up!
    ~Foo() {
        while(size) popBar();
    }

    // all the other special functions need to be custom...
    // we even have to handle cleanup!
    Foo(Foo const &other) {
        try {
            for(std::size_t i = 0; i < other.size; i++) addBar(other[i]);
        } catch(...) {
            while(size) popBar();
            throw;
        }
    }
    Foo(Foo &&other) {
        try {
            for(std::size_t i = 0; i < other.size; i++) addBar(std::move(other[i]));
        } catch(...) {
            while(size) popBar();
            throw;
        }
    }
    Foo &operator=(Foo const &other) {
        while(size > other.size) popBar();
        std::size_t i = 0;
        for(; i < size && i < other.size; i++) operator[](i) = other[i];
        for(; i < other.size; i++) addBar(other[i]);
        return *this;
    }
    Foo &operator=(Foo &&other) {
        while(size > other.size) popBar();
        std::size_t i = 0;
        for(; i < size && i < other.size; i++) operator[](i) = std::move(other[i]);
        for(; i < other.size; i++) addBar(std::move(other[i]));
        return *this;
    }
    // should also add a way to check size, maybe clear, etc.
};

另外,你Bar应该这样写:

class Bar {
    std::string name;
    int number;
public:
    Bar(std::string name, int number) : name(std::move(name)), number(number) { } 
};

和你的main

int main() {
    Foo f; // Foo f(); declares a function!
    f.addBar({"Red", 1});
    return 0;
}

推荐阅读