C++布尔变量的更改

3
我是一个有用的助手,可以为您进行文本翻译。
我有一个C++类,如下所示:
首先是头文件:
class PageTableEntry {
public:

    PageTableEntry(bool modified = true);
    virtual ~PageTableEntry();

    bool modified();
    void setModified(bool modified);

private:
    PageTableEntry(PageTableEntry &existing);
    PageTableEntry &operator=(PageTableEntry &rhs);

    bool _modified;
};

还有 .cpp 文件

#include "PageTableEntry.h"

PageTableEntry::PageTableEntry(bool modified) {
    _modified = modified;
}

PageTableEntry::~PageTableEntry() {}

bool PageTableEntry::modified() {
    return _modified;
}
void PageTableEntry::setModified(bool modified) {
    _modified = modified;
}

我在涉及_modified的.cpp文件中的所有3行上设置了断点,以便我可以准确地看到它们何时被设置/更改/读取。顺序如下:

  1. 构造函数中的断点被触发。确认已将_modified变量设置为true
  2. 访问器中的断点被触发。_modified变量为FALSE!

每个PageTableEntry实例都会出现这种情况。类本身不会更改该变量-其他东西会更改。不幸的是,我不知道是什么。该类使用new动态创建,并被传递(作为指针)到各种STL结构中,包括向量和映射。修改器从未被我的代码调用过(我还没有到达那个阶段),STL结构也不应该能够调用,由于在修改器上永远不会触发断点,因此我只能假设它们没有。

显然,在某些情况下,私有变量可以在不经过类的修改器的情况下更改,由谁知道什么情况触发,但我无法想象它可能是什么。有什么想法吗?

更新: 每个阶段的this的值:
构造函数1:0x100100210
构造函数2:0x100100400
访问器1:0x1001003f0
访问器2:0x100100440

更新2:
(显示PageTableEntry被访问的代码)

// In constructor:
    _tableEntries = std::map<unsigned int, PageTableEntry *>();

// To get an entry in the table (body of testAddr() function, address is an unsigned int:
    std::map<unsigned int, PageTableEntry *>::iterator it;
    it = _tableEntries.find(address);
    if (it == _tableEntries.end()) {
        return NULL;
    }
    return (PageTableEntry *)&(*it);

// To create a new entry:
    PageTableEntry *entry = testAddr(address);
    if (!entry) {
        entry = new PageTableEntry(_currentProcessID, 0, true, kStorageTypeDoesNotExist);
        _tableEntries.insert(std::pair<unsigned int, PageTableEntry *>(address, entry));
    }

这些是导致问题的PageTableEntry对象存储和检索STL结构的唯一点。所有其他函数都使用testAddr()函数来检索条目。

无关:由于C ++现在有65663个问题,到目前为止已经问了164个问题,这意味着仅仅今天C ++标记的问题数量超过了16位无符号整数。有用吗?不。有趣吗?是的。 :)


这可能是 C++ 的 As-If-Broken 规则的一个实例。这个规则允许编译器将一个正确的程序转化为一个不正确的程序,特别是在优化时。 - jww
5个回答

9

你的调试器可能没有正确报告值(这在优化构建中并不罕见,甚至是预期的),或者你的程序中存在其他内存损坏问题。你展示的代码基本上是正确的,应该按照你的期望运行。


针对你的“UPDATE2”进行编辑:
问题出在这一行:

return (PageTableEntry *)&(*it);

*it的类型是std::pair<unsigned const, PageTableEntry*>&,因此你实际上是将一个std::pair<unsigned const, PageTableEntry*>*重新解释为一个PageTableEntry*。请将该行更改为:

return it->second;

请留意代码库中的其他强制类型转换。需要进行强制类型转换本身就是一种编码异味(即“code smell”),使用错误的强制类型转换可能会导致未定义行为,例如在这里看到的内存损坏。使用 C++ 样式的强制类型转换而不是 C 样式的强制类型转换可以轻松找到代码库中出现强制类型转换的位置,以便容易地进行审核(提示,提示)。


它并没有被优化,而且可能是调试器没有正确报告(我正在使用Clang/LLDB)。但是:程序的逻辑取决于该值,如果变量未正确初始化为false,则程序将以应该失败的方式失败。因此,使用该类的代码也会得到false值。我还尝试使用GCC/GDB,它报告了完全相同的现象... - jstm88
@jfm429:好的,一切都听起来越来越像内存损坏了。 - ildjarn
没错,就是这样。傻眼 我要说C风格的转换有时是有益甚至必要的,但在这种情况下显然没有帮助。 :) - jstm88

4

std::map<>::find() 返回一个 iterator,当对其进行解引用时返回一个 std::map<>::value_type。在这种情况下,value_type 是一个 std::pair<>。您返回的是该 pair 的地址,而不是 PageTableEntry。我认为您需要以下内容:

// To get an entry in the table (body of testAddr() function, address is an unsigned int:
std::map<unsigned int, PageTableEntry *>::iterator it;
it = _tableEntries.find(address);
if (it == _tableEntries.end()) {
    return NULL;
}
return (*it).second;

P.S.:C风格的强制转换是有害的。使用C++的强制转换,编译器将会发出诊断信息。 :)

哦,看起来当我正在输入我的答案时,@ildjarn已经抢先一步了。+1 ildjarn :) - Void
我给你点赞了,因为“C风格的强制类型转换是邪恶的”;-] - ildjarn
另外,正确的回答稍有迟缓也要加上+1。还有,通过C++转换,您是指dynamic_cast吗?我的大部分经验都在C语言中(其中C风格的转换显然是唯一的方法)和Objective-C中(在那里转换只是为了风格而必要)。我也曾有人告诉我,在C++中使用指针是不好的,智能指针是唯一正确的方式,所以... :P - jstm88
1
@jfm429:谢谢你的支持:) dynamic_cast是标准C++转换之一,其他的包括static_castconst_castreinterpret_cast。例如,如果您用static_cast<PageTableEntry*>(&(*it))替换了您的C样式转换,则编译器会出现不兼容的类型转换错误。 C样式转换禁用所有类型检查,并允许您基本上做任何您想要的事情,这就是为什么您没有收到错误的原因。网络上有大量关于标准C ++转换的信息。关于智能指针,我也非常喜欢它们:) - Void

3

尝试在每个断点处查看this的值。


哦嗯...这个this改变了(请参见主描述中的更新)-尽管复制/赋值运算符被有意地设置为私有。 - jstm88

0

如果您正在使用STL容器,那么复制构造函数和赋值运算符都会被频繁使用。也许如果您向我们展示这些代码,我们就能看出问题所在。


@Xeo:参数的const属性并不是一个因素;实际上这些是类的复制构造函数和赋值运算符声明。C++03标准中的§12.8/2规定:“如果类X的非模板构造函数的第一个参数是类型为X&const X&volatile X&const volatile X&的引用,并且要么没有其他参数,要么所有其他参数都有默认参数,则该构造函数是复制构造函数”。 - ildjarn
我故意将复制/赋值构造函数设为私有(并且没有实现);为了使程序正常运行,该类不能被复制。然而,请参见我上面发布的更新——看起来这个类确实被复制了,不知道是怎么回事... - jstm88
@jfm429:对我来说,这更像是内存损坏,因为该类是不可复制的。如果您想要进一步的反馈,您需要发布更多展示该类如何使用的代码。 - ildjarn
@ildjarn:哦,知道了,谢谢你的引用。:) 对不起,我忽略了那个“private”关键字... - Xeo
@jfm429:我更新了我的答案以回应你的新补充。 - ildjarn
显示剩余2条评论

0

你能给这个类添加另一个唯一的值来跟踪PageTableEntry吗? 我知道我曾经遇到过类似的问题,真正的问题是有多个看起来相同的条目,断点可能会在我没有意识到的情况下切换PageTableEntry。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接