使用 c++ 类的意外输出

Unexpected output with c++ class

本文关键字:意外 输出 c++ 使用      更新时间:2023-10-16

这是我的 c++ 代码:

class base
{
public:
    int bval;
    base(){ bval=0;}
    void give() { std::cout<<bval<<":"; }
};
void SomeFunc(base *arr,int size)
{
    for(int i=0; i<size; i++,arr++)
        std::cout<<arr->bval;
    std::cout<<"n";
    for(int i=0; i<size; i++,arr++)
        arr->give();
    std::cout<<"n";
}
void test_case4()
{
    base BaseArr[5];
    SomeFunc(BaseArr,6);
}

我正在为上述代码获得以下输出:

000003379188
0:-1079809464:134515567:134515888:0:-1079809336:
为什么

第二行与第一行不同,为什么我在SomeFunc中得到第 6 个循环的输出,而该位置尚未分配,我的意思是没有代码供 give(( 函数执行。

我知道的另一件事是,对象的 sizeof 运算符仅给出其数据元素的大小,而不是对象包含的函数。因此,如果函数不在对象内存空间内,那么它们存储在哪里?

编辑:

我故意第 6 次增加 arr,只是为了检查执行不在第 6 位的函数时会发生什么give()

请参阅对齐姆卡里昂库回复的评论。也请回答我问题的第一部分。

您正在递增arr指针并超过arr指向的原始数组的大小。此外,正如 Cem 指出的那样,函数的值必须是 5 而不是 6。

你的数组,BaseArr 有 5 个元素,而不是 6 个。其上限为4。

base BaseArr[5];
SomeFunc(BaseArr,5); //should fix it.

编辑:
对于为什么你会得到输出:在 C 数组中没有固定的限制,你可以很容易地越界而不会得到任何错误。结果通常是灾难性的。你永远不会知道会发生什么。

编辑2:
今天我的思维工作得特别慢,现在我明白你为什么困惑了。好的,即使 arr 指向的对象无效。它仍然是一个内存位置。在调用 arr->give 时,您实际上是在调用类似于 give(arr( 的函数。由于 arr 只是指向内存位置调用的指针,因此是有效的,并且不会像在 C 中那样引发任何错误。但是,某些调试器能够注意到您越界。为此,始终建议使用载体。

或者,您可以使用类型安全的模板。

template<size_t size> void SomeFunc(Base (const &arr)[size]) {
    //...
}

大小将由编译器自动推断。

为什么程序不崩溃?
C/C++ 语言不对数组进行任何边界检查。这取决于操作系统,以确保您访问有效的内存。

您正在声明一个基于堆栈的数组(大小为 5(。在数组边界之外访问只是访问已分配的堆栈空间的另一部分(大多数操作系统通常为堆栈保留一定部分内存(。幸运的是,您正在访问一个越界数组索引(6(,它属于这个预先分配的堆栈空间,因此它不会崩溃,而是返回该特定内存位置中存在的垃圾数据。

上面只是对发生的事情的逻辑解释,但事实是,

访问通过其边界的数组是未定义的行为,因此不可能定义和推理未定义的行为。时期!

如果函数不在对象内存空间内,那么它们存储在哪里?
C++ 标准未指定成员函数的存储位置。此行为作为编译器的实现详细信息被省略。因此,它可能因编译器而异。

正如您正确所说,与成员变量不同,每个对象都没有成员函数的副本。您可以像free functions一样考虑成员函数,但在一个方面是特殊的,即隐式this指针作为参数传递给它们。

所有编译的代码(包括成员函数(都作为被调用的text segmentcode segment进入内存的一部分。这个内存区域独立于Heap(a.k.a Freestore in C++)StackData/BSS段,这些段保存动态分配的对象、本地声明的对象和全局或静态对象。

希望能回答您的问题。