c++ - 按值传递可调用对象,将其分配给指针成员

标签 c++

我们从一个分包商处收到代码,主要执行以下操作:

class Callable
{
public:
    void operator()(int x)
    {
        printf("x = %d\n", x);
    }
};

template<typename T>
class UsesTheCallable
{
public:
    UsesTheCallable(T callable) :
            m_callable(NULL)
    {
        m_callable = &callable;
    }

    ~UsesTheCallable() {}

    void call() { (*m_callable)(5); }

private:
    T* m_callable;
};

这让我觉得这是未定义的代码......它们按值将 T 传递给 UsesTheCallable 构造函数,然后分配给 m_callable 成员到参数的地址,它应该超出构造函数末尾的范围,所以每当我调用 UsesTheCallable::call() 时,我都在作用于一个不再存在的对象.

所以我尝试了这个主要方法:

int main(int, char**)
{
    UsesTheCallable<Callable>* u = NULL;

    {
        Callable c;
        u = new UsesTheCallable<Callable>(c);
    }

    u->call();

    delete u;

    return 0;
}

在调用 UsesTheCallable::call() 之前,我确保 Callable 对象超出范围,所以我应该调用那时我实际上并不拥有的内存功能。但是代码有效,并且 Valgrind 没有报告内存错误,即使我将一些成员数据放入 Callable 类并使 operator() 函数作用于该成员数据。

我认为此代码是未定义行为是否正确?根据 Callable 是否有成员数据(例如私有(private) int 变量或其他东西),此代码的“定义性”是否有任何差异?

最佳答案

是的,这是未定义的行为。在构造函数 callable 的右括号被销毁后,您就有了一个悬空指针。

您没有看到不利影响的原因是您确实没有在实例超出范围后使用该实例。函数调用运算符是无状态的,因此它不会尝试访问它不再拥有的内存。

如果我们向可调用对象添加一些状态,例如

class Callable
{
    int foo;
public:
    Callable (int foo = 20) : foo(foo) {}
    void operator()(int x)
    {
        printf("x = %d\n", x*foo);
    }
};

然后我们使用

int main()
{
    UsesTheCallable<Callable>* u = NULL;
    {
        Callable c(50);
        u = new UsesTheCallable<Callable>(c);
    }
    u->call();
    delete u;
    return 0;
}

然后你可以看到这个bad behavior .在那次运行中,它输出 x = 772773112,这是不正确的。

关于c++ - 按值传递可调用对象,将其分配给指针成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38774955/

相关文章:

c++ - 函数不是 std 的元素

c++ - 使用 QMathGL 连接信号和槽

c++ - 搜索数据文件 : coding in python vs c++

c++ - LLVM 优化器不能处理简单的情况?

接口(interface)的 C++ 模板特化

c++ - 使用快速排序排序不会给出排序数组

c++ - 在两个 C++ 程序之间交换消息

c++ - C++ 中的匿名数组

c++ - Microsoft Visual Studio 中的 QWT 直方图和立即关闭的 Qt 插件

c++ - XPath 表达式失败。 (C 中的 libxml2)