简体   繁体   English

在类和构造函数中使用向量时出现分段错误

[英]Segmentation fault when using vectors in the class and constructor

I was doing a list of programming projects, and this project is to make a 15 puzzle (slide puzzle).我在做一个编程项目的清单,而这个项目是做一个15拼图(slide拼图)。 I was working on the project when I hit a small roadblock.当我遇到一个小障碍时,我正在研究这个项目。

My code compiles just fine, but when I run it, I get a segmentation fault at line 12: pos[0] = x;我的代码编译得很好,但是当我运行它时,在第 12 行出现分段错误: pos[0] = x;

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
class Tile{
private:
    vector<int> pos;
    int value;
public:
    Tile(int x, int y, int value_){
        pos[0] = x;
        pos[1] = y;
        value = value_;
    }
    ~Tile(){}
    int getPos(int a){return pos[a];}
    void setPos(int a, int b){pos[a] = b;}
};
int main(){
    Tile tile1(1, 2, 10);
    Tile* t1;
    t1 = &tile1;

    // returns position "x"
    cout << t1->getPos(0);
    return 0;
}

I mean, I could just do the whole project without having to use vectors/arrays to handle the position, but I do still want to know, for my own understanding in the future, why this doesn't work.我的意思是,我可以完成整个项目而不必使用向量/数组来处理位置,但我仍然想知道,为了我将来的理解,为什么这不起作用。

Based on the debug that I ran, the program is having trouble initializing the value of the pos[] vector.根据我运行的调试,程序在初始化 pos[] 向量的值时遇到问题。

Another issue: probably related, I tried setting the size of the vector when it was instantiated.另一个问题:可能相关,我尝试在实例化向量时设置向量的大小。

vector<int> pos(2);

But then I get the debug error:但是后来我得到了调试错误:

error: expected identifier before numeric constant

Not sure whats going on here.不知道这里发生了什么。 I've tried a bunch of different things but I can't seem to figure out why my vectors don't work inside of classes.我尝试了很多不同的东西,但我似乎无法弄清楚为什么我的向量在类中不起作用。

I'm sure there are a hundred ways I could have done this little piece better, and I would love to know how you would have fixed it, but I also need to know what is wrong, specifically in the context of what I have written and tried.我确信有一百种方法我可以把这个小作品做得更好,我很想知道你会如何修复它,但我也需要知道什么是错的,特别是在我写的内容的背景下并尝试过。

Thanks.谢谢。

I tried setting the size of the vector when it was instantiated.我尝试在实例化时设置向量的大小。

 vector<int> pos(2);

But then I get the debug error:但是后来我得到了调试错误:

 error: expected identifier before numeric constant

That's a compilation error, not a debug error.那是编译错误,而不是调试错误。

You can't initialise members like that.你不能像那样初始化成员。 However, you can (and should) initialise them using the parent constructor:但是,您可以(并且应该)使用父构造函数初始化它们:

Tile(int x, int y, int value_)
    : pos(2)
{
    pos[0] = x;
    pos[1] = y;
    value = value_;
}

Currently you're just leaving your vector empty then accessing (and writing to!) elements that don't exist.目前,您只是将向量留空,然后访问(并写入!)不存在的元素。

You really don't want a vector for this, anyway: that's a lot of dynamic allocation.无论如何,你真的不想要一个向量:那是很多动态分配。 How about a nice array?一个漂亮的数组怎么样? Or just two int s.或者只是两个int

As mentioned in other answers, your vector is empty and your code is attempting to assign non-existent elements.正如其他答案中提到的,您的向量为空,您的代码试图分配不存在的元素。

The solution is to always use initialisers instead of assignment.解决方案是始终使用初始化程序而不是赋值。 Rewrite your constructor as follows:重写你的构造函数如下:

Tile(int x, int y, int value) :
    pos{x, y},
    value{value} {}

Note that the constructor body is now empty .请注意,构造函数体现在是空的 All initialisation happens where it should — in the initialiser list.所有初始化都发生在它应该发生的地方——在初始化列表中。

Apart from that, your class does not need an explicitly defined destructor;除此之外,您的类不需要显式定义的析构函数; the default destructor works just fine.默认的析构函数工作得很好。

There are other issues with this class — for instance, what happens when the user does tile.setPos(3, 4) ?这个类还有其他问题——例如,当用户执行tile.setPos(3, 4)时会发生什么? A rule of thumb of good API design is to make it impossible to misuse the API.良好 API 设计的一个经验法则是避免滥用 API。

Here's how I would write your Tile class instead:下面是我将如何编写您的Tile类:

struct Tile {
    int x;
    int y;
    int value;

    Tile(int x, int y, int value) : x{x}, y{y}, value{value} {}
};

The getter and setter in your case wasn't really doing any meaningful work.你的情况下的 getter 和 setter 并没有真正做任何有意义的工作。 There's an argument to be made to hide all data members behind accessors to future-proof access control.有一个论点将所有数据成员隐藏在访问者后面,以实现面向未来的访问控制。 I'm no longer convinced this is actually useful but just in case, here's a solution with that, too:我不再相信这实际上很有用,但以防万一,这里也有一个解决方案:

class Tile {
    int x_;
    int y_;
    int value_;

public:
    Tile(int x, int y, int value) : x_{x}, y_{y}, value_{value} {}

    int x() const { return x; }
    int& x() { return x; }

    int y() const { return y; }
    int& y() { return y; }

    int value() const { return value; }
};

This makes x and y readable and writable (via assignment: tx() = 42; ), and value only readable.这使得xy可读和可写(通过赋值: tx() = 42; ),并且value仅可读。 Other APIs are possible, with different sets of trade-offs.其他 API 也是可能的,但要进行不同的权衡。 The important thing is to be consistent.重要的是要保持一致。

Your constructor doesn't set the size, so when you try to access/modify its contents, you are probably getting the exception.您的构造函数没有设置大小,因此当您尝试访问/修改其内容时,您可能会遇到异常。

Tile(int x, int y, int value_) : pos(2) {
    pos[0] = x;
    pos[1] = y;
    value = value_;
}

You can use the initialization list of the constructor to call the vector 's constructor, as in the code above.您可以使用构造函数的初始化列表来调用vector的构造函数,如上面的代码所示。

There are couple of issue in the given code, which I have resolved and added comment in the code.给定的代码中有几个问题,我已经解决并在代码中添加了注释。

Issue in setPos and getPos might raise segmentation fault must be handle. setPosgetPos可能会引起必须处理的分段错误。

Added checks for the same.添加了相同的检查。

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
class Tile{
private:
    vector<int> pos;
    int value;
public:

    Tile(int x, int y, int value_){
        pos.push_back(x); // this is equivalent to pos[0] = x, in this case 
        pos.push_back(y); // this is equivalent to pos[0] = y, in this case
        value = value_;
    }

    ~Tile(){}

    int getPos(int a){
        if(a >= pos.size()){
            return -1; // if a is greater than size then pos[a] will raise the segmentation fault
        }
        return pos[a];
    }
    void setPos(int a, int b){
        if(a >= pos.size()){
            pos.resize(a+1); // to avoid segmentation fault, we are increasing the size if the given index is higher
            // resize initialise the value with 0 as default value.
        }
        pos[a] = b;
    }
};
int main(){
    Tile tile1(1, 2, 10);
    Tile* t1;
    t1 = &tile1;

    // returns position "x"
    cout << t1->getPos(0);
    return 0;
}

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

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