【问题标题】:std::bind a member function to an instance at nullptr causing seemingly random this pointerstd::bind a member function to an instance at nullptr 导致看似随机的 this 指针
【发布时间】:2013-10-06 15:08:39
【问题描述】:

我已经在 gcc-4.8(通过 Coliru)和 Visual Studio 2013 RC 上测试了以下程序:

#include <iostream>
#include <functional>

using namespace std;

struct foo {
    void bar() {
        cout << "this = " << this << endl;
    }
};

int main() {
    try {
        foo *ptr = nullptr;
        function<void ()> fun = bind(&foo::bar, *ptr);
        fun();
    } catch (const bad_function_call &e) {
        // never reached
        cout << "bad_function_call thrown: " << e.what() << endl;
    } 

    cin.get();
}

我知道我在这里通过取消引用 nullptr 导致了未定义的行为,但我不理解我的代码的输出。在我的理解中,这应该导致一个 bad_function_call (因为这是调用这个 std::function 时应该抛出的,从我的猜测)或者至少打印“this = 0”。

它没有。输出是“this =”,后跟一些在我测试的两个编译器上都不是 nullptr 的指针。但是,访问它会导致分段错误。

标准中是否有条款规定了这一点?还是只是实现定义的“未定义行为”?

编辑:作为补充:以下代码在我的机器上输出“this = 0”:

foo *ptr = nullptr;
ptr->bar();

【问题讨论】:

    标签: c++ c++11 undefined-behavior


    【解决方案1】:

    发生的情况是bind 存储了参数的副本。参数是foo 类型(因为您正在传递*ptr),因此制作了一个副本。当然,副本获得了一个无效的参数作为源,但它没有被使用,因此这似乎有效。结果,foo 的新实例存储在绑定对象中,这就是您看到的地址。

    当您说您看到分段错误时,您指的是您的真实代码,而不是您在此处给出的示例,对吗?在您的真实代码中,我猜 copy-ctor 似乎可以工作,但是会创建一个实例,当您访问它的(可能是无效的)成员时会导致分段错误。

    【讨论】:

    • 那么传递 ref(*foo) 应该会导致“this = 0”成为输出吗?打算做一些测试。编辑:确实如此。
    • 分段错误是关于在 foo::bar 中访问它。我想知道为什么它没有抛出 std::bad_function_call,因为恕我直言,这很有意义。
    • @DominikLohmann bad_function_call 保留用于函数指针本身为 0,但您传递的是有效的成员函数指针。您只是没有传入有效实例作为第一个参数。
    【解决方案2】:

    “未定义”表示未定义。除非你的编译器记录了它的作用,否则推理当你有未定义的行为时会发生什么是徒劳的。

    【讨论】:

    • 虽然我在标准方面同意你的观点,但就具体实现而言,了解某些东西为什么有效(即使是奇怪的)可能很有趣。
    • @MatthieuM。 - “有趣”并不否定“徒劳”。 &lt;g&gt;
    • 所有的知识都值得拥有 -- Anafiel Delaunay
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    • 2022-12-27
    • 2022-12-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2021-04-22
    相关资源
    最近更新 更多