gpt4 book ai didi

C++:导致访问冲突的 vector 元素分配

转载 作者:行者123 更新时间:2023-11-27 22:38:25 25 4
gpt4 key购买 nike

当在 C++ 中将字符串分解为单独的行和参数(作为二维 vector )时,它会在尝试解析函数之间的 vector 时产生有趣的访问冲突问题。在代码示例中,已多次尝试确保传入和传出函数的数据是独立的对象,绝不是引用。

segregate.hpp

#pragma once

#include <vector>
#include <string>

/*
Purpose:
To to take a whole file as a string,
and break it up into individual words
*/

namespace Segregate {
// Module types
typedef std::vector< std::string > ParamArray;
struct StrCommand{
unsigned long line;
ParamArray param;
};
typedef std::vector< StrCommand > StrCommands;

bool IsParamBreak(char val);
bool IsLineBreak(char val);

ParamArray Parameterize(std::string str);
StrCommands Fragment(std::string str);
}


#include "./segregate.cpp"

分离.cpp

#include "./segregate.hpp"

namespace Segregate{
bool IsParamBreak(char val){
if (val == ' '){
return true;
}else if (val == '\t'){
return true;
}

return false;
};
bool IsLineBreak(char val){
if (val == '\n'){
return true;
}

return false;
};

// Splits a single line into individual parameters
ParamArray Parameterize(std::string str){
str.append(" "); // Ensures that the loop will cover all segments
unsigned long length = str.size();
unsigned long comStart = 0;
ParamArray res;


// Ignore carrage returns
// Windows artifact
if (str[0] == '\r'){
comStart = 1;
}


// Ignore indentation
// Find the start of actual content
while (comStart < length && IsParamBreak(str[comStart])){
comStart++;
}

// Count the number of parameters
unsigned long vecLen = 0;
for (unsigned long i=comStart; i<length; i++){
if ( IsParamBreak(str[i]) ){
vecLen++;
}
}
res.reserve(vecLen);


// Scan will fail if there is no data
if (length == 0){
return res;
}


// Slice the the string into parts
unsigned long toIndex = 0;
unsigned long cursor = comStart;
for (unsigned long i=cursor; i<length; i++){
if (IsParamBreak(str[i]) == true){
// Transfer the sub-string to the vector,
// Ensure that the data is it's own, and not a reference
res[toIndex].reserve(i-cursor);

// Error here
res[toIndex].assign( str.substr(cursor, i-cursor) );

cursor = i+1;
toIndex++;
}
}

return res;
};


StrCommands Fragment(std::string str){
str.append("\n"); // Ensures that the loop will cover all segments
unsigned long length = str.size();

// Result
StrCommands res;


// Count lines
// Ignoring empty lines
unsigned long vecLen = 1;
for (unsigned long i=0; i<length; i++){
if (IsLineBreak(str[i])){
vecLen++;
}
}
res.reserve(vecLen);


// Ignore 'empty' strings as they may cause errors
if (vecLen == 0){
return res;
}


// Read lines
unsigned long toIndex = 0;
unsigned long cursor = 0;
for (unsigned long i=0; i<length; i++){
if (IsLineBreak(str[i])){

// Error here
res[toIndex].param = ParamArray( Parameterize( std::string(str.substr(cursor, i-cursor)) ) );
res[toIndex].line = i+1;

// Ignore blank lines
if (res[toIndex].param.size() == 0){
vecLen--;
}else{
toIndex++;
}
cursor = i+1;
}
}


// Shrink the result due to undersizing for blank lines
res.reserve(vecLen);

return res;
};
}

内存访问冲突通常发生在第 66 和 108 行(当元素数据本地存储在 vector 中时)。它似乎发生在分配阶段,正如通过使用中间临时变量在解析后直接存储结果所推断的那样。该错误也可能发生在 vector::reserve() 期间,但发生频率较低。


注意:在 Windows 上没有直接的错误消息:

Exception thrown at 0x00A20462 in fiber.exe: 0xC0000005: Access violation reading location 0xBAADF009.

仅在使用“Visual Studio Code 的 C/C++ 扩展”调试时可见,在正常终端执行中不可见。
但是在 Ubuntu 上它输出:

Segmenation fault (core dump)

最佳答案

您在 vector 上调用 reserve,它分配内存来存储您的对象但不构造它们。当您随后尝试使用您尚未构建的对象的方法时,它很可能会崩溃。

有 2 种可能的解决方案,要么调用 resize 而不是 reserve,要么调用 push_back 在 vector 的末尾构造新对象。

关于C++:导致访问冲突的 vector 元素分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51277613/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com