【问题标题】:C++ Boolean Variables ChangingC++ 布尔变量更改
【发布时间】:2011-08-03 05:53:47
【问题描述】:

我有一个 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;
}

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

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

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

显然有一些“陷阱”,在某些情况下,可以在不通过类的 mutator 的情况下更改私有变量,由不知道是什么情况触发,但我无法想象它会是什么。有什么想法吗?

更新: 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() 函数来检索条目。

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

【问题讨论】:

  • 这可能是 C++ As-If-Broken 规则的一个实例。这是允许编译器将正确程序变成错误程序的规则,尤其是在优化时。

标签: c++ variables private self-modifying


【解决方案1】:

要么你的调试器没有正确报告值(不是闻所未闻,甚至在优化的构建中是预期的),要么你的程序中的其他地方有内存损坏。您显示的代码或多或少都很好,应该按照您的预期运行。


EDIT 对应于您的“UPDATE2”:
问题出在这一行:

return (PageTableEntry *)&(*it);

*it 的类型是std::pair&lt;unsigned const, PageTableEntry*&gt;&amp;,因此您实际上是将std::pair&lt;unsigned const, PageTableEntry*&gt;* 重新解释为PageTableEntry*。将该行更改为:

return it->second;

留意您的代码库中的其他演员表。首先需要强制转换是一种代码异味,错误地进行强制转换的结果可能是未定义的行为,包括如您在此处看到的那样表现为内存损坏。使用 C++ 风格的转换而不是 C 风格的转换,可以轻松找到代码库中发生转换的位置,以便轻松查看它们(提示,提示)。

【讨论】:

  • 它没有优化,它可能是调试器没有正确报告它(我正在使用 Clang/LLDB)。但是:程序的逻辑取决于该值,如果变量未正确初始化为 false,程序会完全按照它应该的方式失败。因此,使用该类的代码也得到了 false 值。我也尝试使用 GCC/GDB,它报告了完全相同的现象......
  • @jfm429 :很公平。你说的每一句话听起来越来越像内存损坏......
  • 是的,就是这样。 derp 我会说 C 风格的强制转换有时是有益的,甚至是必要的,但显然在这种情况下它们没有帮助。 :)
【解决方案2】:

std::map&lt;&gt;::find() 返回一个 iterator,当取消引用时返回一个 std::map&lt;&gt;::value_type。在这种情况下,value_typestd::pair&lt;&gt;。您返回的是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 :)
  • 我为“C 风格的演员阵容是邪恶的”+1 了你;-]
  • 并且 +1 也是正确的(如果迟到了)答案。另外,通过 C++ 演员表,您是指 dynamic_cast 吗?我的大部分经验是在 C(C 风格的转换显然是唯一的方法)和 Objective-C(只有风格需要转换)。我也有人告诉我,C++ 中的指针是邪恶的,而智能指针是 only 正确的方法,所以... :P
  • @jfm429:感谢您的 +1 :)。 dynamic_cast 是标准 C++ 类型转换之一。其他的是static_castconst_castreinterpret_cast。例如,如果你用static_cast&lt;PageTableEntry*&gt;(&amp;(*it)) 替换了你的 C 风格转换,编译器会在不兼容的类型转换上阻塞。 C 风格的强制转换禁用所有类型检查,让您基本上可以做任何您想做的事情,这就是您没有收到错误的原因。 Web 上有大量关于标准 C++ 类型转换的信息。关于智能指针,我也非常喜欢它们。 :)
【解决方案3】:

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

【讨论】:

  • 嗯...this 更改(请参阅主要描述中的更新) - 即使复制/分配运算符被有意设为私有。
【解决方案4】:

如果您使用的是 STL 容器,那么复制构造函数和赋值运算符都会被大量使用。也许如果您向我们展示这些代码,我们会发现有问题。

【讨论】:

  • 我怀疑复制构造函数和赋值运算符故意未定义,以使类不可复制和不可赋值。
  • @Xeo : const- 参数的性质不是一个因素;这些实际上是类的复制 c'tor 和赋值运算符声明。 C++03 标准中的 §12.8/2 写道:“如果类 X 的第一个参数的类型为 X&amp;const X&amp;volatile X&amp;const volatile X&amp;,要么没有其他参数,要么所有其他参数都有默认参数。"
  • 我故意将复制/赋值构造函数设为私有(并且没有实现);不能复制用于运行该类的程序。曾经。但是,请参阅我在上面发布的更新 - 看起来课程确实被复制了,不知何故......
  • @jfm429 :在我看来,它更像是内存损坏,因为该类是不可复制的。如果您需要进一步的反馈,您需要发布更多代码来展示该类的使用方式。
  • 发布的代码:每个条目的创建/检索都由那些代码段处理,封装在方法中。在程序终止之前,永远不会删除条目。
【解决方案5】:

您能否向该类添加另一个唯一值以跟踪 PageTableEntry s? 我知道我遇到过这样的问题,真正的问题是有多个看起来相同的条目,并且断点可能会在我没有意识到的情况下切换 PageTableEntry。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 2019-08-11
    相关资源
    最近更新 更多