简体   繁体   English

c ++中奇怪的分段错误

[英]weird segmentation fault in c++

i have the following method : 我有以下方法:

string Company::cheap(list<Candidate*>& candidates) {
    candidates.sort(candidateSalaryCompare);
    for (std::list<Candidate*>::iterator iter = candidates.begin(); iter
    != candidates.end(); ++iter) {
    }
    int m(candidates.front()->getExpectedSalary());
    list<Candidate*> potentialList;
    for (std::list<Candidate*>::iterator iter = candidates.begin(); (*iter)->getExpectedSalary()
    == m && iter != candidates.end(); ++iter)
        potentialList.push_back(*iter);
    if (potentialList.size() > 0)
        potentialList.sort(candidateIdCompare);
    return potentialList.front()->getId();
}

running it as is and my program works, but if i remove the empty FOR loop in the beginning (which doesn't do anything) i get a segmentation fault. 按原样运行它,我的程序工作,但如果我在开头删除空FOR循环(没有做任何事情),我得到一个分段错误。 any clues ? 任何线索?

EDIT 编辑

candidate class, and actually i'm not sure at what line i'm getting the segfault, i'm using eclipse and the debugger doesn't seem to work 候选类,实际上我不知道我在哪个行得到段错误,我正在使用eclipse并且调试器似乎不起作用

#include "../include/Candidate.h"
#include <iostream>
#include "../include/AppLogger.h"
#include <sstream>

Candidate::Candidate(string id, list<Skill> skills, list<
        string> desiredJobs, double expectedSalary) :
        id_(id), dateJoined_(), skills_(skills),
        desiredJobs_(desiredJobs), expectedSalary_(expectedSalary),
        originalSalary_(expectedSalary), gotJob_(0) {
}


void Candidate::compromise(const DateTime& currentDate) {
    double salaryAfter30(0.9*this->originalSalary_);
    double salaryAfter60(0.8*this->originalSalary_);
    double salaryAfter90(0.7*this->originalSalary_);
    Timespan duration = currentDate - this->dateJoined_;
    if (duration.days() == 30 || duration.days() == 60 || duration.days() == 90) {
        if (duration.days() == 30 && (this->expectedSalary_
                == this->originalSalary_)) {
            this->expectedSalary_ = salaryAfter30;
            std::stringstream sstm;
            sstm << "Candidate "<< this->getId() <<" is willing to compromise, and his expected salary is " <<this->expectedSalary_ << ".";
            CAppLogger::Instance().Log(sstm.str(),
                    Poco::Message::PRIO_WARNING);
            return;
        }
        else if (duration.days()==30)
            poco_bugcheck_msg("Error, 30 days passed, worker already compromised");
        if (duration.days() == 60 && (this->expectedSalary_ == salaryAfter30)) {
            this->expectedSalary_ = salaryAfter60;
            std::stringstream sstm;

            sstm << "Candidate "<< this->getId() <<" is willing to compromise, and his expected salary is " <<this->expectedSalary_ << ".";
            CAppLogger::Instance().Log(sstm.str(),
                    Poco::Message::PRIO_WARNING);
            return;
        }
        else if (duration.days()==60)
            poco_bugcheck_msg("Error, 60 days passed, worker already compromised");

        if ((duration.days() == 90) && (this->expectedSalary_ == salaryAfter60)) {
            this->expectedSalary_ = salaryAfter90;
            std::stringstream sstm;
            sstm << "Candidate "<< this->getId() <<" is willing to compromise, and his expected salary is " <<this->expectedSalary_ << ".";
            CAppLogger::Instance().Log(sstm.str(),
                    Poco::Message::PRIO_WARNING);
            return;
        }
        else if (duration.days()==90)
            poco_bugcheck_msg("Error, 90 days passed, worker already compromised");

    }
    else poco_bugcheck_msg("Error, worker told to compromise when not needed");


}

list<Skill> Candidate::getSkills() const {
    return this->skills_;
}

list<string> Candidate::getDesiredJobs() const {
    return this->desiredJobs_;

}
double Candidate::getExpectedSalary() const {
    return this->expectedSalary_;
}
DateTime Candidate::getDateJoined() const {
    return this->dateJoined_;
}
DateTime Candidate::getDateLeft() const {
    return this->dateLeft_;
}
void Candidate::setDateLeft(const DateTime& date) {
    this->dateLeft_ = date;
}
string Candidate::getId() const {
    return this->id_;
}

void Candidate::setDateJoined(const DateTime& date) {
    this->dateJoined_=date;
    this->setGotJob();
}

void Candidate::setGotJob() {
    if (this->gotJob_==1)
        std::cerr<<"error, setting gotJob while already has job"<<std::endl;
    this->gotJob_=1;
}
bool Candidate::gotJob() const {
    return this->gotJob_;
}
void Candidate::setQl(double ql){
        jobQl_=ql;
}

int Candidate::getQl() const{
    return this->jobQl_;
}

after applying the supplied solutions i get the following error : 应用提供的解决方案后,我收到以下错误:

assignment2(48823) malloc: *** mmap(size=140734799806464) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

EDIT 编辑

changed int m to double m and now it seems to work because get expected salary returns a double but why did it cause that error ? 将int m改为double m,现在它似乎有效,因为获得预期的薪水会返回一个双倍,但为什么会导致该错误呢?

Please, look at Cris Hopman answer here , as his answer is much more complete and detailed than mine pointing to other issues that can/will cause undefined behavior (segmentation fault) in the original code. 请看这里的 Cris Hopman答案,因为他的答案比我的答案更加完整和详细,指出了原始代码中可能/将导致未定义行为(分段错误)的其他问题。

This condition is wrong: 这种情况是错误的:

for (std::list<Candidate*>::iterator iter = candidates.begin(); (*iter)->getExpectedSalary()
== m && iter != candidates.end(); ++iter)

You should reorder so that the test for end() comes before the dereference and keep the short circuit evaluation. 您应该重新排序,以便在取消引用之前进行end()测试并保持短路评估。 As it is, you are dereferencing a pointer past the end of the container: 实际上,您正在取消引用超过容器末尾的指针:

for (std::list<Candidate*>::iterator iter = candidates.begin(); 
     iter != candidates.end() && (*iter)->getExpectedSalary() == m; ++iter)

Let me break this up a little... 让我稍微分解一下......

...
    int m(candidates.front()->getExpectedSalary());

You assume that candidates is nonempty, this is fine if it is documented but I would add 你认为候选人是非空的,如果记录在案,但是我会补充说这很好

assert(!candidates.empty())

at the beginning of the function. 在功能的开头。 This both enforces the constraint and makes the constraint clear to anyone reading the code. 这两者都强制执行约束,并使读取代码的任何人都明白约束。

Second, getExpectedSalary() returns a double that you are converting to an int... more on this later. 其次,getExpectedSalary()返回一个你要转换为int的double ...稍后详细介绍。

    list<Candidate*> potentialList;
    for (std::list<Candidate*>::iterator iter = candidates.begin(); 
        (*iter)->getExpectedSalary() == m && iter != candidates.end(); ++iter)
       potentialList.push_back(*iter);

Two problems here: iter != candidates.end() should be the first part of the conditional, otherwise you may dereference an invalid iterator in the first part. 这里有两个问题: iter != candidates.end()应该是条件的第一部分,否则你可能会在第一部分中取消引用无效的迭代器。 Second, the equality check is bad. 其次,平等检查很糟糕。 It may fail for even the first item in the list because if d is a double then it is not necessarily the case that (int)d == d . 即使列表中的第一项也可能失败,因为如果d是double,则不一定是(int)d == d The point is that m should be a double. 关键是m应该是双倍的。 With that change, the test may still fail unexpectedly since it is a floating point comparison, see here . 通过该更改,测试可能仍然意外失败,因为它是浮点比较,请参见此处

    if (potentialList.size() > 0)
        potentialList.sort(candidateIdCompare);
    return potentialList.front()->getId();

This is inconsistent. 这是不一致的。 In the if you assume that potentialList might be empty, but in the return you assume that it can't be empty. if你假设potentialList可能是空的,但在返回中你假设它不能为空。 In fact, potentialList should not be empty (as it should at the very least contain candidates.front()) and so this should be changed to: 实际上,potentialList不应该为空(因为它至少应该包含candidate.front()),所以这应该改为:

    assert(!potentialList.empty());
    potentialList.sort(candidateIdCompare);
    return potentialList.front()->getId();

If you make only that change, you will find that the assert will fail. 如果只做了那个改变,你会发现断言会失败。 You will then realize that potentialList is empty because of the conversion from double to int discussed above. 然后您将意识到potentialList是空的,因为上面讨论了从double到int的转换。

Finally, it appears that you are storing monetary values as floating point. 最后,您似乎将货币值存储为浮点数。 This can cause problems, be careful. 这可能会引起问题,要小心。 It is often much safer to use only fixed-point for such, but is not necessary. 为此只使用定点通常更安全,但不是必需的。

As a last note, this function itself is overly complex. 最后一点,这个功能本身过于复杂。 The below should work (no guarantees)... 以下应该工作(没有保证)......

string Company::cheap(list<Candidate*>& candidates) {
    typedef list<Candidate*> list_t;
    assert(!candidates.empty());

    candidates.sort(candidateSalaryCompare);
    pair<list_t, list_t> rng = equal_range(candidates.begin(), candidates.end(),
        candidates.front(), candidateSalaryCompare);

    assert(rng.first != rng.second);
    return (*min_element(rng.first, rng.second, candidateIdCompare))->getId();
}

This also conveniently offloads all the salary comparison to one other function and so it only has to be done correctly once. 这也方便地将所有工资比较卸载到另一个功能,因此只需要正确完成一次。

Your second for loop, specifically the condition, could be dangerous: 你的第二个循环,特别是条件,可能是危险的:

(*iter)->getExpectedSalary() == m && iter != candidates.end()

This is because it deferences iter to compare against m before actually checking if the iterator is valid. 这是因为它deferences iter对比较m实际检查,如果迭代器是否有效之前 You need to invert the order of the checks so the condition becomes: 您需要反转检查的顺序,以便条件变为:

iter != candidates.end() && (*iter)->getExpectedSalary() == m

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM