【问题标题】:array of unknown size as class member for making objects of array at runtime(object creating time)未知大小的数组作为类成员,用于在运行时制作数组对象(对象创建时)
【发布时间】:2019-08-11 19:57:29
【问题描述】:

我想构造一个大小未知的数组类, 我想制作数组对象,其大小将在我创建对象(运行时)时初始化

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;
 }
};

它说是无效使用非静态数据成员的错误,我做错了什么(我应该知道什么)?。

【问题讨论】:

  • 这样的动态数组创建在某些 C++ 标准中是非法的,并且赋值根本不保留任何内存。建议:对此类任务使用std::vector
  • @ThomasLang 感谢您的回复,哪个分配根本不保留任何内存,关于在运行时创建数组大小我应该知道什么?
  • 你应该知道的是,你需要使用std::vector。这就是它存在的目的:创建一个在运行时确定的大小的数组。打开你的 C++ 书籍到解释如何使用std::vector 的章节,然后阅读它。
  • @SamVarshavchik 先生,我知道如何使用向量,我想创建一个我自己的向量我被迭代器困住了。我正在尝试创建自己的矢量容器,其中包含一个大小会自行增加的数组。我见过这些魔法。我想看看魔法的背后。我知道我没有资格提出这样的要求,所以请尝试一下。
  • 矢量不是这样工作的。它们为它们的值动态分配一个缓冲区,并且它们还需要正确地实现诸如构造和销毁向量中的单个元素之类的事情,这本身实际上是一个相当高级的主题。向量不包含在运行时确定的大小数组。这不是他们的工作方式。

标签: c++ arrays class oop compiler-errors


【解决方案1】:

你不能有类似的东西

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

在 C++ 中。

这个东西叫做variable-length array,它在C99中得到支持。

顺便说一句,这是我所知道的唯一一个在 C99 中受支持而在 C++17 中不受支持的东西:)。

std::vector 是一个不错的选择。

如果您在编译时知道数组的大小,则可以使用std::array

【讨论】:

    【解决方案2】:

    我想构造一个大小未知的数组类

    (我应该知道什么)?

    您应该知道这在 C++ 中是不可能的。所有类的大小都是编译时常量。

    我想创建数组对象,其大小将在我创建对象(运行时)时初始化

    您需要动态分配数组。

    一个简单的解决方案:

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

    【讨论】:

    • @ParsuramKailasa 它动态分配数组。
    • 所有类的大小都是编译时间常数,我还是不明白,请你在我的代码上下文中解释一下,我在哪里做这个,谢谢
    • @ParsuramKailasa 您正在尝试创建一个在编译代码时其大小未知的数组(即数组的大小不是编译时间常数)。因为大小取决于变量,所以只有在您的代码运行时才知道。这在 C++ 中是不允许的。
    • @ParsuramKailasa Vectors 使用一种称为动态内存分配的技术,您也可以直接在您的课程中使用动态内存分配,但使用矢量更容易,因为所有的辛苦工作都已为您完成。
    • @ParsuramKailasa BTW 如果您确实将所有数组大小作为编译时常量,您可以提供一个与std::array 相同的简单模板类。
    【解决方案3】:

    @eerorika 和@Nestor 有很好的答案。在这里添加它们是我前段时间做的一个向量的简单实现,你可以作为参考。

    正如您将看到的,拥有可变长度数据结构的一种基本方法是删除底层数组并在需要更多或更少内存时创建一个更大的数组。

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 2020-10-15
      相关资源
      最近更新 更多