std::vector 段错误 =-操作未初始化 space
Segfault with std::vector =-operation to uninitialized space
当我使用 =-运算符将包含 std::vector 的结构复制到未初始化的内存时,出现分段错误。
关键代码如下所示:
template<typename T>
ComponentContainer
{
T* buffer;
size_t capacity;
size_t m_size;
public:
ComponentContainer();
~ComponentContainer();
size_t size();
void resize(size_t size);
T & operator[](size_t index);
};
template<typename T>
void ComponentContainer<T>::resize(size_t newSize)
{
if(this->m_size >= newSize)
{
this->m_size = newSize;
}
else
{
if(this->capacity < newSize)
{
const size_t newCapacity = capacity*2;
T* newBuffer = (T*)malloc(newCapacity*sizeof(T));
for(size_t i = 0; i<m_size; i++)
{
// checks if this->buffer[i] is valid intialized memory
if(pseudo_checkIfElementIsInitialized(i))
{
// when this is uncommented no segfault happens
//new (&newBuffer[i]) T();
newBuffer[i] = this->buffer[i]; // <- segfault happens here
}
}
this->capacity = newCapacity;
free(this->buffer);
this->buffer = newBuffer;
}
this->m_size = newSize;
}
}
T
类型是一个结构,当我遇到段错误时,它具有 std::vector 个结构。
我怀疑 std::vector =-运算符以某种方式使用了左侧变量 newBuffer[i]
并且由于 newBuffer[i]
未初始化而发生分段错误。
将仅使用函数 T & operator[](size_t index)
的就地新建创建对象。 malloc 应该只分配内存而不初始化任何东西。
我试着写了一个简单的例子,但效果不是很好:
#include <iostream>
#include <vector>
struct Hello
{
Hello()
{
std::cout << "constructor" << std::endl;
}
~Hello()
{
std::cout << "destructor" << std::endl;
}
std::vector<double> v = std::vector<double>(1);
};
int main()
{
Hello* buffer = (Hello*)malloc(1*sizeof(Hello));
char* noise = (char*)buffer;
for(size_t i = 0; i<sizeof(Hello); i++)
{
noise[i] = 100;
}
auto tmp = Hello();
tmp.v[0] = 6.6;
//new (&buffer[0]) Hello();
buffer[0] = tmp;
std::cout << buffer[0].v[0] << std::endl;
return 0;
}
在没有段错误的情况下工作正常。我认为这是因为未初始化的内存对于 std::vector =-操作来说是偶然的。
所以
a) 这个理论正确吗
如果是
b) 如何在不为我用作 ComponentContainer
[=21 的 T
的每个 class 使用默认构造函数 (T()
) 的情况下解决此问题=]
嗯,是的。您不能分配给不存在的对象。
取消注释修复它的行!
如果不能默认构造,则复制构造:
new (&newBuffer[i]) T(this->buffer[i]);
如果你做不到,那么,剩下的你就知道了。
The malloc should only allocate the memory without initializing anything.
您是否低估了这句话的分量?您不只是获取内存,然后决定是否使用某些值对其进行初始化。您必须在使用对象之前实际创建对象;这不是可选的。您正在编写 C++,而不是在磁带上操作位和字节:)
当我使用 =-运算符将包含 std::vector 的结构复制到未初始化的内存时,出现分段错误。 关键代码如下所示:
template<typename T>
ComponentContainer
{
T* buffer;
size_t capacity;
size_t m_size;
public:
ComponentContainer();
~ComponentContainer();
size_t size();
void resize(size_t size);
T & operator[](size_t index);
};
template<typename T>
void ComponentContainer<T>::resize(size_t newSize)
{
if(this->m_size >= newSize)
{
this->m_size = newSize;
}
else
{
if(this->capacity < newSize)
{
const size_t newCapacity = capacity*2;
T* newBuffer = (T*)malloc(newCapacity*sizeof(T));
for(size_t i = 0; i<m_size; i++)
{
// checks if this->buffer[i] is valid intialized memory
if(pseudo_checkIfElementIsInitialized(i))
{
// when this is uncommented no segfault happens
//new (&newBuffer[i]) T();
newBuffer[i] = this->buffer[i]; // <- segfault happens here
}
}
this->capacity = newCapacity;
free(this->buffer);
this->buffer = newBuffer;
}
this->m_size = newSize;
}
}
T
类型是一个结构,当我遇到段错误时,它具有 std::vector 个结构。
我怀疑 std::vector =-运算符以某种方式使用了左侧变量 newBuffer[i]
并且由于 newBuffer[i]
未初始化而发生分段错误。
将仅使用函数 T & operator[](size_t index)
的就地新建创建对象。 malloc 应该只分配内存而不初始化任何东西。
我试着写了一个简单的例子,但效果不是很好:
#include <iostream>
#include <vector>
struct Hello
{
Hello()
{
std::cout << "constructor" << std::endl;
}
~Hello()
{
std::cout << "destructor" << std::endl;
}
std::vector<double> v = std::vector<double>(1);
};
int main()
{
Hello* buffer = (Hello*)malloc(1*sizeof(Hello));
char* noise = (char*)buffer;
for(size_t i = 0; i<sizeof(Hello); i++)
{
noise[i] = 100;
}
auto tmp = Hello();
tmp.v[0] = 6.6;
//new (&buffer[0]) Hello();
buffer[0] = tmp;
std::cout << buffer[0].v[0] << std::endl;
return 0;
}
在没有段错误的情况下工作正常。我认为这是因为未初始化的内存对于 std::vector =-操作来说是偶然的。
所以
a) 这个理论正确吗
如果是
b) 如何在不为我用作 ComponentContainer
[=21 的 T
的每个 class 使用默认构造函数 (T()
) 的情况下解决此问题=]
嗯,是的。您不能分配给不存在的对象。
取消注释修复它的行!
如果不能默认构造,则复制构造:
new (&newBuffer[i]) T(this->buffer[i]);
如果你做不到,那么,剩下的你就知道了。
The malloc should only allocate the memory without initializing anything.
您是否低估了这句话的分量?您不只是获取内存,然后决定是否使用某些值对其进行初始化。您必须在使用对象之前实际创建对象;这不是可选的。您正在编写 C++,而不是在磁带上操作位和字节:)