模板中的错误 std::bad_array_new_length

Posted

技术标签:

【中文标题】模板中的错误 std::bad_array_new_length【英文标题】:Error std::bad_array_new_length in a template 【发布时间】:2021-09-16 01:59:24 【问题描述】:

我试图定义自己的类模板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 的那行不是正确的。 知道构造函数按照自己子对象的初始化顺序,第一个要构造的元素就是指针。 由于我正在尝试创建维度为sizeT 元素向量,因此正确地给了我错误,因为我尚未初始化整数大小。 所以我通过换行来解决它。

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

但此时我想知道:为什么,如果我不进行函数调用,知道构造时的大小是未定义的,我不会得到同样的错误?

从逻辑上讲,在这种情况下也应该出现问题,但是似乎一切正常

PS:不要指望我没有处理抛出的异常,代码还没有完全完成,但目前我渴望至少实现三法则。

【问题讨论】:

“似乎有效”是未定义行为的一种非常常见的表现形式。您不能将逻辑应用于未定义的事物。 @molbdnilo 是的,你完全正确。由于我今年才开始用 c++ 编程,您对某种质量的编译器和调试器有什么建议吗?因为我基本上用的是MinGW。 迂腐模式:“类模板”,而不是“模板类”。 @Evg 哎呀,我的错。我没注意到!谢谢 @LukeTheWolf“模板类”和“模板函数”被广泛使用,但是,正如Walter Brown says,单词顺序很重要:“牛奶巧克力”和“巧克力牛奶”非常不同。类模板和函数模板。 【参考方案1】:

在 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 异常又回来了!所以,绝对不能保证!

【讨论】:

非常感谢您的回复!我很高兴听到这不仅仅是我,我想知道输出是否只是 UB 或其他我不知道的结果。再次感谢:D

以上是关于模板中的错误 std::bad_array_new_length的主要内容,如果未能解决你的问题,请参考以下文章

Angular中的模板错误

处理 FreeMarker 模板中的错误都有哪些不同的方法?

Magento 2 模板文件夹中的 PHP 代码给出语法错误

Google App Engine 中的 Django 模板语法错误

Access 模板宏中的 SaveRecord 错误

Sun Studio 12 中的模板编译错误