c++ - 模板中的错误 std::bad_array_new_length

标签 c++ arrays c++11 templates

我试图定义我自己的类模板 Array<T>练习模板的使用。
我生成的代码构建正确,但执行时出现以下错误

terminate called after throwing an instance of 'std::bad_array_new_length'
  what():  std::bad_array_new_length
我想我已经找到了该问题的解决方案,但我很想知道之前的代码中是否存在潜在错误,如果存在,是哪个错误。
这是我之前写的代码:
#include <iostream>

class Empty{
private:
    char error;
public:
    Empty(char e) : error(e) { std::cout << "Azione non disponibile, lista vuota" << std::endl;}
};

template <class T>
class Array;

template <class T>
std::ostream& operator<<(std::ostream&,const Array<T>&);

template <class T>
class Array{
    friend std::ostream& operator<< <T> (std::ostream&,const Array<T>&);
private:
    T* arr;
    unsigned int size;
    unsigned int capacity;

    static T* copia(T* a, unsigned int s, unsigned int c){
        if(c > 0) {
            T* app = new T[c];
            for (int i = 0; i<s; ++i) {
                app[i] = a[i];
            }
            return app;
        }else return nullptr;
    }

public:
    Array(int k = 0, const T& t = T()) : size(k > 0 ? k : 0), capacity(size), arr(k > 0 ? new T[size] : nullptr){
        for (int i = 0; i < k ; ++i) arr[i] = t;
    }

    Array(const Array& a) : size(a.size), capacity(a.capacity), arr(copia(a.arr,a.size,a.capacity)){}

    Array& operator=(const Array& a){
        if(this != &a){
            delete[] arr;
            capacity = size = a.size;
            arr = copia(a.arr,a.size,a.capacity);
        }
        return *this;
    }

    ~Array(){delete[] arr;}

    void pushBack(const T& t) {
        if(size == capacity){
            capacity > 0 ? capacity *= 2 : capacity = 1;
            T* app = copia(arr,size, capacity);
            delete[] arr;
            arr = app;
        }
        ++size;
        arr[size-1] = t;
    }

    T popBack() {
        if (size != 0) {
            T temp = arr[size - 1];
            --size;
            return temp;
        } else throw Empty('e');
    }

};

template <class T>
std::ostream& operator<<(std::ostream& os ,const Array<T>& a){
    for (int i = 0; i < a.size; ++i) {
        os << a.arr[i] << ' ';
    }
    std::cout << std::endl;
    return os;
}

int main(){

    Array<int> a(5,5),e;
    std::cout << a << std::endl;

    a.pushBack(16);
    a.pushBack(17);
    a.pushBack(18);

    std::cout << a << std::endl;

    return 0;
}
如果我在没有 a.pushBack(x) 的情况下运行此代码函数调用,它的工作原理。
只要我插入一个函数调用,我就会在输出中收到该错误。
在调试时,我意识到我写的那行T* arr不是正确的。
知道构造函数遵循其自身子对象的初始化顺序,首先要构造的元素是指针。
由于我正在尝试创建 T 的元素 vector 带尺寸 size ,正确地给了我错误,因为我还没有初始化整数大小。
所以我通过换行解决了这个问题。
template <class T>
class Array{
    friend std::ostream& operator<< <T> (std::ostream&,const Array<T>&);
private:
    unsigned int size;
    unsigned int capacity;
    T* arr;
    ...
};

但此时我想知道:为什么,如果我不进行函数调用,我不会得到同样的错误,因为知道构造时的大小是未定义的?
从逻辑上讲,在这种情况下也应该出现问题,但一切似乎都有效:
enter image description here
PS:不要指望我没有处理抛出的异常,代码还没有完全完成,但目前我热衷于至少实现三规则。

最佳答案

使用 jdoodle.com 中的 GCC 9.1.0 进行编译,我的原始代码始终出现 bad_alloc 运行时异常。
我添加了一个具有不同签名的新构造函数,以便我可以看到 size 的值它用于分配数组
注意:即使这个新 ctor 的存在也阻止了 bad_alloc 错误,无论它是否被调用。

Array(char c, int k = 0, const T& t = T()) : 
    size(k > 0 ? k : 0), 
    capacity(size), 
    arr(DebugInit(size)){
    for (int i = 0; i < k ; ++i) arr[i] = t;
}

T* DebugInit( unsigned long size_init )
{
    std::cout << "DebugInit size_init=" << size_init << " cap=" << capacity << std::endl;
    return size_init > 0 ? new T[size_init] : nullptr;
}
使用这个新 ctor 时,结果似乎是随机的。size_init每次都不同,这与使用尚未初始化的成员字段一致。
原代码中,可能是size碰巧一直有 0 在里面。
通过添加更多代码,即使它从未被调用过,编译版本也会访问一个随机但现在非零的值 size .
这似乎是经典的“未定义行为”。如果您使用 size在它被初始化之前,不能保证里面会有什么。
如果幸运的话,size在初始化之前将始终返回 0,并且您将收到分配错误。
但是对代码的一个小改动可能会开始为 size 返回随机值。 .
如果未初始化size具有比您预期的值大得多的值,您将在稍后或可能永远不会看到问题。
稍微玩弄代码之后, std::bad_alloc 异常又回来了!所以,绝对不能保证!

关于c++ - 模板中的错误 std::bad_array_new_length,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68253560/

相关文章:

c++ - 为什么某些 C++ 标准库 `operator<<` 函数将其流宽度重置为 0?

c++ - 这是在 C++ 中执行 "with"语句的最佳方法吗?

java - 数组是按降序、升序还是无序排序?

javascript - 检查数组列表中的行会 ID

c++ - 在初始化全局变量时使用断言宏

c++ - std::function 的 G++ 问题

c++ - 如果enable_if确定T是一个容器,则启用一个结构体?

c++ - 在 Linux 上使用 boost::serialization 序列化 unique_ptr 的 std::vector 失败

c++ - vk创建交换链KHR : internal drawable creation failed

python - 查询矩阵中的行