所以我正在创建一个函数,只要字符串是一个尚未包含在向量中的唯一字符串,它就会向字符串向量添加一个新字符串。这是我的代码:
void CityMapper::addToVector(string& s)
{
bool newWord = true;
if(numAirports > 0)
{
for(int i = 0; i < numAirports; i++)
{
if(airportNames[i].compare(s) == 0)
newWord = false;
}
}
if(newWord == true)
{
airportNames.pushBack(s);
numAirports++;
}
}
airportNames是字符串的向量。当我运行程序时,它会在Valgrind中出现以下错误:
Process Terminating with default action of signal 11 (SIGSEGV)
Access not within mapped region at address 0x0
在此之前,Valgrind终端出现此错误:
Invalid Read of Size 8
两者都发生在string.compare()行。有谁知道为什么会发生这种情况?我也试过没有&amp;的功能。参数中的符号。
编辑:我接受了德里克的建议并完成了所有更改。现在程序是以不同的方法进行分区,我从文件中读取字符串。以下是该功能的代码:
void CityMapper::getCities()
{
ifstream fin;
fin.open(flightDataFile);
fin >> numAirports;
string tempCity1, tempCity2, tossout;
while(getline(fin, tempCity1, ','))
{
fin.ignore(1);
getline(fin, tempCity2, ',');
fin.ignore(1);
getline(fin, tossout, '\n');
addToVector(tempCity1);
addToVector(tempCity2);
}
}
以下是Valgrind的错误消息:
==8357== Use of uninitialised value of size 8
==8357== at 0x4EF158B: std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357== by 0x402214: CityMapper::getCities() (in
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==
==8357== Invalid read of size 4
==8357== at 0x4EF158B: std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357== by 0x402214: CityMapper::getCities() (in
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
==8357==
==8357==
==8357== Process terminating with default action of signal 11 (SIGSEGV)
==8357== Access not within mapped region at address 0xFFFFFFFFFFFFFFF8
==8357== at 0x4EF158B: std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357== by 0x402214: CityMapper::getCities() (in
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)
答案 0 :(得分:6)
compare
不会导致细分错误。这是你试图在不存在的情况下调用它的对象。作为一般规则:永远不要存储冗余信息(在这种情况下为numAirports
)。如果必须存储冗余信息,则至少应检查一致性。在您上面发布的代码中,格式错误的输入文件会使您的应用程序崩溃。只需完全删除numAirports
,您就不需要它。
相反,请使用以下内容:
void CityMapper::addUnique( const string& name )
{
if ( std::find( airportNames.begin(), airportNames.end(), name )
== airportNames.end() )
{
// Name does not yet exist -> add it
airportNames.push_back( name );
}
}
注意事项:
const
引用。该方法不会改变此参数,而是以编译器可以验证的方式记录它。name
。毕竟,这就是它所代表的。std::find
)。不要试图重新发明轮子。正如评论中所指出的,如果没有令人信服的理由使用std::vector
,您应该查看std::set
或std::unordered_set
。两个容器都存储唯一对象,因此您无需编写自己的addUnique
。
答案 1 :(得分:1)
如果您必须使用std::vector
(而不是std::unordered_set
):
void CityMapper::addToVector(const string& s) // you aren't changing the string, pass it by const-reference
{
std::vector<std::string>::iterator it = std::find(airportNames.begin(), airportNames.end(), s);
if (it == airportNames.end()) // not found, so unique
{
airportNames.push_back(s);
}
}
std::vector
有一个大小成员(因此不需要numAirports
),使用std::find
函数可以消除额外的条件检查。
或者,您可以使用std::unordered_set
或std::set
并完全避免std::find
操作(但是,这会占用更多内存):
void CityMapper::addToVector(const string& s)
{
std::set<std::string> airports(airportNames.begin(), airportNames.end());
airports.insert(s);
airportNames.assign(airports.begin(), airports.end());
}
更好的解决方案是简单地将数据存储在一个集合中以开头:
void CityMapper::addUnique(const string& s)
{
// assume airportNames is defined as a std::set<std::string>
airportNames.insert(s);
}
但是对于你原来的问题:seg错误可能是因为你没有使用std::vector
的实际大小,而是存储一个单独的numAirports
值(可能不是保持同步,如果你进行上述更改是不必要的,所以当你试图访问未分配给向量的内存(并且可能根本没有分配)时,你正在调用未定义的行为。所有这些都随着更好的代码而消失。
修改强>
根据您的其他信息,还应注意您的getCities
功能可以大大简化:
struct line_reader : std::ctype<char>
{
line_reader() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
rc[','] = std::ctype_base::space;
rc[' '] = std::ctype_base::alpha; // allowing city names with spaces
return &rc[0];
}
};
void CityMapper::getCities()
{
ifstream fin(flightDataFile);
line_reader reader;
fin.imbue(std::locale(std::locale(), &reader));
// if using a set
std::copy(std::istream_iterator<std::string>(fin), std::istream_iterator<std::string>(), std::inserter(airportNames, airportNames.begin()));
// or, if using a vector
// NOTE: to keep this exception safe
// (e.g. keep the values in the actual vector unique even if something happens after we've read in the file data,
// pull the values into a temp vector and then swap
std::vector<std::string> temp;
std::copy(std::istream_iterator<std::string>(fin), std::istream_iterator<std::string>(), std::back_inserter(temp));
std::sort(temp.begin(), temp.end());
temp.erase(std::unique(temp.begin(), temp.end()), temp.end());
std::swap(airportNames, temp);
}
答案 2 :(得分:0)
将代码更改为此。
我更改了一些我正在使用airportNames.size()
的东西,它返回airportNames向量中的元素数量。这将防止在向量上调用pop_back或remove但是未更新numAirports时发生任何错误。这是段错误的最可能原因。
我还修正了我希望通过airportNames.push_back()
电话打字错误的内容。您的airportNames.pushBack()
语法不正确。
最后一点只是一种风格,但newWord == true
是多余的,只需说if( newWord)
两个语句都评估为真。
void CityMapper::addToVector(const string& s)
{
bool newWord = true;
for(int i = 0; i < airportNames.size(); ++i)
{
if(s == airportNames[i])
newWord = false;
break;
}
if(newWord)
{
airportNames.push_back(s);
}
}