c ++分段错误将指针传递给函数

Posted

技术标签:

【中文标题】c ++分段错误将指针传递给函数【英文标题】:c++ Segmentation Fault passing in pointer to function 【发布时间】:2013-04-28 21:28:48 【问题描述】:

我正在编写代码来用图像文件中的数据填充纹理类。据我所知,代码和实现是有效的,但是在进入我的程序的主循环时会导致分段错误。这 4 行,删除后,删除了分段错误:

Texture* texture = new Texture(); // Dynamically allocate texture object to texture pointer
bool success = loadTexture(texture, "C:/pathToImage/image.png"); // Function that gets image data
cout << success << endl; // Print out success or not
textures.push_back(*texture); // put texture in a vector of textures

编辑:texture.h

class Texture 
public:
    Texture();
    Texture(const Texture&);
    ~Texture();
    Texture& operator=(const Texture&);
public:
    void init();
    int width, height;
    std::vector<unsigned char> pixmap;
    GLuint id;
;

texture.cpp:(init函数被删掉了,因为它与错误无关,甚至没有被调用。)

Texture::Texture() : width(0), height(0), pixmap(), id(int(-1))
Texture::Texture(const Texture& other) : width(other.width), height(other.height), pixmap(other.pixmap), id(other.id)
Texture::~Texture()

width = 0;
height = 0;
delete &pixmap;
id = int(-1);

Texture& Texture::operator=(const Texture& other) 
width = other.width;
height = other.height;
pixmap = other.pixmap;
id = other.id;

我假设它与纹理指针有关,但是我尝试了几种方法来做同样的事情,它们都导致了相同的分段错误。有人能解释一下是什么原因造成的吗?

【问题讨论】:

请提供更多代码。到目前为止,您所展示的内容不足以看到问题。 我猜 Texture 不遵循三规则。 @Kyurem 你想要什么?这是我拥有的唯一导致错误的代码 - 删除它会删除错误。 杀死指针。在这里没用。 您动态分配纹理,然后将其副本放入纹理中,这很奇怪,尽管不一定是错误的。 【参考方案1】:

您的错误是因为 Texture 类没有遵循三规则。 '任何具有析构函数、复制构造函数或赋值运算符之一的类很可能需要全部三个'。

What is The Rule of Three?

具体可能发生的情况是,由于您尚未定义复制构造函数,因此您的对象被浅复制到向量中。这导致两个纹理对象共享相同的像素图数据。当其中一个对象被破坏时,这会使另一个对象中的像素图数据无效。

例如,复制构造函数的一种可能性是 this

Texture::Texture(const Texture& other) : width(other.width), height(other.height), pixmap(NULL), id(other.id)

    pixmap = new unsigned char[width*height];
    memcpy(pixmap, other.pixmap, width*height);

只有一种方法可以做到。 cHao 提出了其他可能性。

【讨论】:

根据是否应该共享pixmap 数组,您还可以使用指向它的智能指针(需要 C++11 或 Boost,或其他一些具有良好共享指针的库),或者vector&lt;char&gt;,将为您复制。两者都可以避免甚至需要析构函数,更不用说其他两个了。 致力于实施上述“三法则”。直到现在我才意识到这一点,感谢您的提醒。 同样的错误仍然适用,即使在实施了三规则之后。有关新的纹理类,请参阅上面的更新帖子 @ColinMoore:构造函数和赋值运算符是否为pixmap 分配了一个新数组?仅复制指针会给您带来与默认函数相同的问题。 Texture operator=(Texture); 应该是Texture&amp; operator=(const Texture&amp;); 也许你可以给我们看一下析构函数、复制构造函数等的代码。【参考方案2】:

(注意:我假设Texture() 正确分配了一个数组,或者至少将指针清零。如果它不这样做,那是你的问题。如果它只做后者,任何尝试使用数组会导致 UB,但至少析构函数不会。)

如前所述,pixmap 没有得到正确处理。即使一个临时对象被销毁,它指向的数组也会被释放,而在 pixmap 中具有相同指针的每个其他实例中都会有悬空指针。

您可以添加一个复制构造函数和赋值运算符,为您复制指向的数组,满足“三规则”。但在我看来,更清洁的解决方案是遵循“rule of zero”。 :) 使用自动进行复制和销毁的类型,您就不需要特殊的函数来处理复制、赋值和销毁。

如果要复制数组,std::vectorstd::array 可以轻松做到这一点。 (您会使用哪一个可能取决于数组是否需要调整大小。std::vector 将始终有效,但std::array 可能更适合静态大小数组的一些奇怪情况。)

如果您需要共享数据,std::shared_ptr (C++11) 或 boost::shared_ptr 将跟踪有多少指针。只有当它的所有shared_ptrs 都被销毁时,数组才会被释放。

请注意,使用这些解决方案中的任何一种,都会为您处理数组的内存。如果这是析构函数等的唯一原因,那么您不再需要一个,因此“三规则”不再起作用。

【讨论】:

我应用了你所说的,用矢量替换了像素图。发生同样的错误,这次是在程序的前面。 @ColinMoore:你用NULL 初始化它,就像你用指针做的那样?那不会飞让它自己创建,在你使用它之前,resize 它的大小可以容纳你需要的数据。对我来说,这似乎是您的主要问题;我没有看到你甚至用可用值填充了指针pixmap 如果您查看我帖子中更新的构造函数,我想它会回答您的问题。我使用默认构造函数对其进行初始化。而且您看不到我在哪里填充了可用值,因为这是在传递指向纹理的指针的函数中完成的。 @ColinMoore 你不会删除向量。如果使用向量,则可以删除析构函数、复制构造函数和赋值运算符。我认为您应该花时间阅读我发布的关于三规则的链接。或者读一本书,任何好的 C++ 书籍都会广泛涉及这个主题,如果不了解资源管理和对象复制的问题,你真的无法正确编程 C++。 @ColinMoore:请不要更改问题中已有的代码。它使所有答案无效;现在看起来我在告诉你做你已经在做的事情。如果您想提及您的更改,请在问题的现有内容之后添加“更新:”或其他内容。

以上是关于c ++分段错误将指针传递给函数的主要内容,如果未能解决你的问题,请参考以下文章

将指向数组的指针传递给函数时出现分段错误(C++)

通过指针或引用将映射传递给函数?

C在函数中传递二维数组会给我分段错误

在 C 中创建大型数组时出现分段错误

GTK3 将结构传递给回调函数 - 发生异常,分段错误

Int 指针不为空,可以打印,但不能在不引发分段错误的情况下传递给函数