简体   繁体   English

未知大小的数组作为类成员,用于在运行时创建数组对象(对象创建时)

[英]array of unknown size as class member for making objects of array at runtime(object creating time)

I want to construct a class of an array whose size is not known, i want to make objects of array whose size would be initialized at the time when i would create an object(runtime)我想构造一个大小未知的数组类,我想创建数组对象,其大小将在我创建对象时初始化(运行时)

class array_class{
public:
 int size_of_array;
 int arr[size_of_array];
 array_class(int p_size_of_array){ //constructor
     this->size_of_array=p_size_of_array;
 }
};

it say's error of invalid use of non static data member, what wrong am i doing(what should i have known)?.它说无效使用非静态数据成员的错误,我做错了什么(我应该知道什么)?。

You can't have something like你不能有类似的东西

void foo(int n)
{
    int vals[n];
}

in C++.在 C++ 中。

The thing is called variable-length array and it's supported in C99.这个东西被称为可变长度数组,它在 C99 中得到支持。

By the way, it is the only thing I know which is supported in C99 and not supported in C++17 :).顺便说一下,这是我所知道的唯一在 C99 中受支持而在 C++17 中不受支持的东西 :)。

std::vector is a nice alternative. std::vector是一个不错的选择。

If you know the size of an array at the compile time, you may use std::array .如果您在编译时知道数组的大小,则可以使用std::array

I want to construct a class of an array whose size is not known我想构造一个大小未知的数组类

(what should i have known)? (我应该知道什么)?

You should have known that is not not possible in C++.您应该知道这在 C++ 中是不可能的。 The size of all classes is compile time constant.所有类的大小都是编译时常量。

i want to make objects of array whose size would be initialized at the time when i would create an object(runtime)我想创建数组对象,其大小将在我创建对象(运行时)时初始化

You need to allocate the array dynamically.您需要动态分配数组。

A simple solution:一个简单的解决方案:

struct array_class {
    std::vector<int> arr;
    array_class(int p_size_of_array) : arr(p_size_of_array) {}
};

@eerorika and @Nestor have good answers. @eerorika 和 @Nestor 有很好的答案。 To add to them here is a simple implementation of a vector i did some time ago you can take as a reference.要添加到它们这里是我前段时间做的向量的简单实现,您可以作为参考。

As you will see a basic way to have a variable length data structure, is to delete the underlying array and create a larger one if more or less memory is needed.正如您将看到的具有可变长度数据结构的基本方法是删除底层数组并在需要更多或更少内存时创建一个更大的数组。

#pragma once

#include <ostream>
#include <string>
#include <initializer_list>
#include <stdexcept>

static constexpr size_t min_sz = 5;

template<typename T>
class Vector
{
public:
    class ConstIterator;
    class Iterator;
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = value_type&;
    using const_reference = const value_type &;
    using pointer = value_type *;
    using const_pointer = const value_type *;
    using iterator = Vector::Iterator;
    using const_iterator = Vector::ConstIterator;

/// constructors, destructor, assign
    Vector()
    {
        allocEmpty(min_sz);
    }

    Vector(Vector<value_type> &vec)
    {
        allocEmpty(vec.max_sz);

        for (size_type i = 0; i < vec.sz; ++i)
            values[i] = vec.values[i];

        sz = vec.sz;
    }

    Vector(size_type size)
    {
        allocEmpty(size);
    }

    Vector(const std::initializer_list<value_type> &list)
    {
        allocEmpty(list.size());

        size_type i = 0;
        for (const auto &val : list)
        {
            values[i] = val;
            ++i;
        }
        sz = list.size();
    }

    ~Vector()
    {
        delete[] values;
    }

    Vector &operator=(const Vector &other)
    {
        reserve(other.sz);

        for (size_type i = 0; i < other.sz; ++i)
            values[i] = other.values[i];

        sz = other.sz;

        return *this;
    }

/// element access
    reference operator[](size_type position)
    {
        if (position >= sz)
            throw std::out_of_range ("operator[] out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));

        return values[position];
    }

    const_reference operator[](size_type position) const
    {
        if (position >= sz)
            throw std::out_of_range ("operator[] out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));

        return values[position];
    }

    const_reference front() const
    {
        if (sz == 0)
            throw std::out_of_range ("front called on empty container");
        return values[0];
    }

    const_reference back() const
    {
        if (sz == 0)
            throw std::out_of_range ("back called on empty container");
        return values[sz - 1];
    }

    pointer data()
    {
        if (sz > 0)
            return values;

        return nullptr;
    }

    const_pointer data() const
    {
        if (sz > 0)
            return values;

        return nullptr;
    }

/// capacity
    size_type size() const
    {
        return sz;
    }

    size_type capacity() const
    {
        return max_sz;
    }

    bool empty() const
    {
        return (sz == 0);
    }

    void reserve(size_type size)
    {
        if (size <= min_sz)
            return;

        value_type *newArray = new value_type[size];

        for (size_type i = 0; i < sz; ++i)
            newArray[i] = values[i];

        delete[] values;

        values = newArray;
        max_sz = size;
    }

    void shrink_to_fit()
    {
        size_type newSize = (sz >= min_sz) ? sz : min_sz;
        value_type *newArray = new value_type[newSize];

        for (size_type i = 0; i < sz; ++i)
            newArray[i] = values[i];

        delete[] values;

        values = newArray;
        max_sz = newSize;
    }

/// modifiers
    void push_back(const value_type &value)
    {
        if (sz >= max_sz)
            reserve(max_sz * 2);

        values[sz] = value;
        ++sz;
    }

    void resize(size_type count)
    {
        reserve(count);
        sz = count;
    }

    void resize(size_type count, const value_type &value)
    {
        reserve(count);
        for (size_type i = sz; i < count; ++i)
            values[i] = value;

        sz = count;
    }

    void insert(size_type position, const value_type &value)
    {
        if (position > sz)
            throw std::out_of_range ("insert out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));

        if (sz >= max_sz)
            reserve(max_sz * 2);

        for (size_type i = sz; i > position; --i)
            values[i] = values[i - 1];

        values[position] = value;
        ++sz;
    }

    iterator insert(const_iterator pos, const_reference val) 
    {
        auto diff = pos - begin();
        if (diff < 0 || static_cast<size_type>(diff) > sz)
            throw std::runtime_error("Iterator out of bounds");

        size_type current = static_cast<size_type>(diff);
        if (sz >= max_sz)
            reserve(max_sz * 2);

        for (size_t i = sz; i-->current;)
            values[i + 1] = values[i];

        values[current] = val;
        ++sz;
        return iterator(values + current);
    }

    void erase(size_type position)
    {
        if (position >= sz)
            throw std::out_of_range ("erase out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));

        for (size_type i = position; i < sz - 1; ++i)
            values[i] = values[i + 1];

        --sz;
    }

    iterator erase(const_iterator pos) 
    {
        auto diff = pos - begin();
        if (diff < 0 || static_cast<size_type>(diff) >= sz)
            throw std::runtime_error("Iterator out of bounds");

        size_type current = static_cast<size_type>(diff);
        for (size_type i = current; i < sz - 1; ++i)
            values[i] = values[i + 1];

        --sz;
        return iterator(values + current);
    }

    void pop_back()
    {
        if (sz == 0)
            throw std::out_of_range ("pop_back on empty container");

        if (sz > 0) --sz;
    }

    void clear()
    {
        sz = 0;
    }

/// iterators
    iterator begin()
    {
        if (sz == 0)
            return end();

        return iterator(values);
    }

    iterator end()
    {
        return iterator(values + sz);
    }

    const_iterator begin() const
    {
        if (sz == 0)
            return end();

        return ConstIterator(values);
    }

    const_iterator end() const
    {
        return ConstIterator(values + sz);
    }

/// private section
private:
    void allocEmpty(size_type size)
    {
        auto newSize = (size > min_sz) ? size : min_sz;
        sz = 0;
        values = new value_type[newSize];
        max_sz = newSize;
    }

private:
    value_type *values;

    size_type sz;
    size_type max_sz;

/// iterator implementations
public:
    class Iterator
    {
    public:
        using value_type = Vector::value_type;
        using reference = Vector::reference;
        using pointer = Vector::pointer;
        using difference_type = Vector::difference_type;
        using iterator_category = std::forward_iterator_tag;

    public:
        Iterator()
        {
            ptr = nullptr;
        }

        Iterator(pointer ptr)
        {
            this->ptr = ptr;
        }

        reference operator*() const
        {
            return *ptr;
        }

        pointer operator->() const
        {
            return ptr;
        }

        iterator& operator++()
        {
            ++ptr;
            return *this;
        }

        iterator operator++(int)
        {
            iterator it = *this;
            ++ptr;
            return it;
        }

        iterator operator+ (difference_type difference) const
        {
            return iterator(ptr + difference);
        }

        bool operator==(const const_iterator &it) const
        {
            return it == ptr;
        }

        bool operator!=(const const_iterator &it) const
        {
            return it != ptr;
        }

        operator const_iterator() const
        {
            return const_iterator(ptr);
        }

    private:
        pointer ptr;
    };

    class ConstIterator
    {
    public:
        using value_type = Vector::value_type;
        using reference = Vector::const_reference;
        using pointer = Vector::const_pointer;
        using difference_type = Vector::difference_type;
        using iterator_category = std::forward_iterator_tag;

    public:
        ConstIterator()
        {
            ptr = nullptr;
        }

        ConstIterator(pointer ptr)
        {
            this->ptr = ptr;
        }

        reference operator*() const
        {
            return *ptr;
        }

        pointer operator->() const
        {
            return ptr;
        }

        const_iterator& operator++()
        {
            ++ptr;
            return *this;
        }

        const_iterator operator++(int)
        {
            const_iterator it = *this;
            ++ptr;
            return it;
        }

        bool operator==(const const_iterator &it) const
        {
            return it.ptr == ptr;
        }

        bool operator!=(const const_iterator &it) const
        {
            return it.ptr != ptr;
        }

        Vector::difference_type operator-(const const_iterator &rop)
        {
            return ptr - rop.ptr;
        }

    private:
        pointer ptr;
    };

};

/// non-member functions
template<typename T>
bool operator==(const Vector<T> &lop, const Vector<T> &rop)
{
    if (lop.size() != rop.size()) return false;

    for (size_t i = 0; i < lop.size(); ++i)
    {
        if (lop[i] != rop[i])
            return false;
    }
    return true;
}

template<typename T>
std::ostream& operator<<(std::ostream &out, const Vector<T> &vec)
{
    out << '[';
    for (size_t i = 0; i < vec.size(); ++i)
    {
        if (i > 0) out << ", ";
        out << vec[i];
    }
    out << ']';
    return out;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM