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

Jer*_*Lee 7 c++ pointers vector segmentation-fault

我正在编写一个编程项目列表,而这个项目是制作15个拼图(幻灯片拼图)的。当我遇到一个小障碍时,我正在从事该项目。

我的代码编译得很好,但是当我运行它时,在第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;
}
Run Code Online (Sandbox Code Playgroud)

我的意思是,我可以不必使用向量/数组来处理整个项目就可以完成整个项目,但是我仍然想知道,就我自己的理解而言,这为什么行不通。

基于我运行的调试,程序在初始化pos []向量的值时遇到了麻烦。

另一个问题:可能与此有关,我尝试在实例化矢量时设置其大小。

vector<int> pos(2);

但是然后我得到调试错误:

error: expected identifier before numeric constant

不知道这是怎么回事。我已经尝试了很多不同的方法,但是似乎无法弄清楚为什么向量不能在类内部工作。

我敢肯定,有一百种方法可以使这件小作品做得更好,我很想知道您将如何解决它,但是我还需要知道什么地方出了问题,特别是在我写的内容中并尝试了。

谢谢。

Lig*_*ica 5

我尝试在实例化矢量时设置其大小。

vector<int> pos(2);
Run Code Online (Sandbox Code Playgroud)

但是然后我得到调试错误:

error: expected identifier before numeric constant
Run Code Online (Sandbox Code Playgroud)

那是编译错误,不是调试错误。

您不能像这样初始化成员。但是,您可以(并且应该)使用父构造函数对其进行初始化:

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

当前,您只是将向量留空,然后访问(并写入!)不存在的元素。

无论如何,您确实不想要向量:这是很多动态分配。一个好的数组怎么样?或仅两个int秒。


Kon*_*lph 5

如其他答案中所述,您的向量为空,并且您的代码正在尝试分配不存在的元素。

解决方案是始终使用初始化程序而不是分配。重写您的构造函数,如下所示:

Tile(int x, int y, int value) :
    pos{x, y},
    value{value} {}
Run Code Online (Sandbox Code Playgroud)

请注意,构造函数主体现在为。所有初始化都在应有的地方进行-在初始化列表中。

除此之外,您的类不需要显式定义的析构函数。默认的析构函数工作正常。

此类还有其他问题-例如,当用户这样做时会发生什么tile.setPos(3, 4)?良好的API设计的经验法则是避免滥用API。

这是我改写您的Tile课程的方法:

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

    Tile(int x, int y, int value) : x{x}, y{y}, value{value} {}
};
Run Code Online (Sandbox Code Playgroud)

您的案例中的getter和setter并没有真正做任何有意义的工作。有一个论点是将所有数据成员隐藏在访问器后面,以实现面向未来的访问控制。我不再相信这实际上是有用的,但以防万一,这也是一种解决方案:

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; }
};
Run Code Online (Sandbox Code Playgroud)

这使得xy可读且可写(通过赋值:)t.x() = 42;,并且value仅可读。其他API可能会有所不同,需要权衡取舍。重要的是要保持一致。

  • _“有一个论点是将所有数据成员隐藏在访问者的后面,以进行面向未来的访问控制。” _我个人认为,[瘦小的吸气剂正在(如果可能是巧妙的话)起到了与该目标相反的作用]( /sf/answers/847561781/)。 (2认同)