[英]Why is stack smashing detected if an empty array[] is initiated in the constructor < 2 inside a class
...用这个最小的可执行代码来重现错误和...
#include <iostream>
class arrayClass
{
private:
int _elements;
int _array[];
public:
arrayClass()
: _elements(32)
{
//If i is smaller than 2 the "Stack Smashing Detected" error shows up, why is that?
//If i is 2 or more, no error appears
//(f.e. int i = 0 or int i = 1 doesn't work, int i = 2 or higher works - why is that?)
for(int i = 0; i < _elements; ++i){
_array[i] = 0;
}
}
int get(int index){
return _array[index];
}
};
int main()
{
arrayClass arr;
std::cout << arr.get(2) << std::endl;
return 0;
}
...无论我是使用初始化列表还是使用 fe32 或任何数字的属性本身来启动 _elements 都没有关系。
如果除了 arrayClass() 构造函数之外,我还传递 int 值来构造arrayClass(int)
,则不会出现错误。
如果我只用一个值构造 arrayClas(int),它也可以只与第二个插槽一起使用。
所以我的问题是:为什么我不能启动默认array[]
的第一个和第二个数组槽?
或者反过来,为什么可以将一个空array[]
分配给没有值的 class 而不是 fe _array[32] 没有错误但分配array[0] = 0;
和array[1] = 0;
?
(是的,我知道向量,出于各种原因,我需要使用 arrays)
因为你从来没有为数组分配 memory ,所以一切都是未定义的行为。 我什至不知道没有大小说明符的int _array[]
会评估什么。 我稍后会查一下。
将您的构造代码更改为“新”数组。 并有一个析构函数来删除它。
class arrayClass
{
private:
int _elements;
int* _array;
public:
arrayClass()
: _elements(32)
{
_array = new int[_elements];
memset(_array, '\0', sizeof(array[0])*_elements);
}
int get(int index){
return _array[index];
}
~arrayClass()
{
delete [] _array;
}
};
或者,如果您可以拥有固定数量的元素,请在声明数组时明确调整数组的大小:
class arrayClass
{
private:
int _array[32];
public:
arrayClass()
: _array() // this will zero-init the array
{
}
int get(int index){
return _array[index];
}
};
int _array[];
是一个灵活的数组,在标准 C++ 中是不允许的。 它不分配 memory 所以当你访问数组中的任何元素时,你有未定义的行为。
我知道向量,出于各种原因,我需要使用 arrays
实际上,有效的理由很少,所以我认为你提到的各种理由都是人为的。 如果需要将数据传递给 function,如void func(int*, size_t elements);
,您仍然可以使用std::vector<int>
。 只需将其data()
和size()
作为 arguments 传递。
在 C++ 中,您通常应该在这种情况下使用std::vector<int>
。
例子:
#include <iostream>
#include <vector>
class arrayClass
{
private:
std::vector<int> _array;
public:
arrayClass(size_t s = 32)
: _array(s)
{}
size_t size() const {
return _array.size();
}
int get(size_t index) const {
return _array[index];
}
};
int main()
{
arrayClass arr;
std::cout << arr.get(10) << std::endl;
return 0;
}
另一种方法是,如果您的arrayClass
具有固定数量的元素:
#include <array>
class arrayClass
{
private:
std::array<int, 32> _array;
public:
arrayClass()
: _array{}
{}
size_t size() const {
return _array.size();
}
int get(size_t index){
return _array[index];
}
};
如果std::vector
消耗的额外空间(通常是 4 或 8 个字节)是一个真正的问题,您可以制作一个类似的 class ,它只存储指向分配的 memory 的指针和大小。 它可能看起来像这样(但没有像vector
那样增长/收缩的能力):
#include <iostream>
#include <algorithm>
#include <memory>
#include <type_traits>
template<typename T, std::enable_if_t<std::is_default_constructible_v<T>>* = nullptr>
class arrayClass {
public:
using value_type = T;
arrayClass(size_t size = 32) :
_size(size),
_array(std::make_unique<T[]>(_size))
{}
// copy constructor
arrayClass(const arrayClass& rhs) :
_size(rhs._size),
_array(std::make_unique<T[]>(_size))
{
static_assert(std::is_copy_assignable_v<T>, "T must be copy assignable");
std::copy(rhs._array.get(), rhs._array.get() + _size, _array.get());
}
arrayClass(arrayClass&&) = default; // move constructor
// copy assignment operator
arrayClass& operator=(const arrayClass& rhs) {
*this = arrayClass(rhs); // copy construct and move assign
return *this;
}
arrayClass& operator=(arrayClass&&) = default; // move assignment operator
// accessing element at index
T& operator[](size_t index) { return _array[index]; }
const T& operator[](size_t index) const { return _array[index]; }
// bounds checking access to element
T& at(size_t idx) {
if(idx >= _size)
throw std::out_of_range(std::to_string(idx) + ">=" + std::to_string(_size));
return _array[idx];
}
const T& at(size_t idx) const {
if(idx >= _size)
throw std::out_of_range(std::to_string(idx) + ">=" + std::to_string(_size));
return _array[idx];
}
size_t size() const { return _size; }
// support for iterating over the elements in the array
const T* cbegin() const { return _array.get(); }
const T* cend() const { return _array.get() + _size; }
const T* begin() const { return cbegin(); }
const T* end() const { return cend(); }
T* begin() { return _array.get(); }
T* end() { return _array.get() + _size; }
private:
size_t _size;
std::unique_ptr<T[]> _array;
};
using intArray = arrayClass<int>;
int main() {
try {
intArray arr1(10);
// the added iterator support makes range-based for-loops possible:
for(int& v : arr1) {
static int i=0;
v = ++i;
}
intArray arr2;
arr2 = arr1; // copy assign
for(size_t i=0; i < arr2.size(); ++i) {
std::cout << arr2[i] << '\n'; // access using operator[] works too
}
std::cout << arr2.at(10) << '\n'; // throws out_of_range exception
}
catch(const std::out_of_range& ex) {
std::cerr << ex.what() << '\n';
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.