首页 > 解决方案 > 在 C++11 中重构 C 函数输入输出和输入破坏参数

问题描述

我必须使用几个像往常一样具有输入、输入-输出和输出参数的遗留 C 函数,并且我想将它们包装在 C++ 函数中。

double为了简单起见,我在这里用作参数,但我认为这个问题对于涉及大量成员的参数也是有效的struct。)

C 函数如下所示:

void Cfun(double* in_a, double* io_b, double* out_c, double* in_destr_d){}

在文档中,它说第一个参数a是输入参数,b是输入输出,c是输出,并且d是一个输入参数,返回时将包含未指定的(垃圾)值。(并且所有的指针都必须是非空的,并且只取一个元素,所以不涉及数组。)

在 C++ 中,很明显可以Cfun通过以下方式进行重构而不损失:

double fun0(double a, double& b, double d){
    double c;
    Cfun(const_cast<double*>(&a), &b, &c, &d);
    return c;
}

哪个应该有效,但也将涉及原始 C 版本中没有的副本。因此,鉴于我们对Cfun(文档+我们知道我们在做什么)的了解,一个更好的版本可能是:

double fun1(double const& a, double& b, double& d){
    double c;
    Cfun(const_cast<double*>(&a), &b, &c, &d);
    return c;
}

即,a被提升为 const 引用,bd被提升为引用并c被提升为返回值。

这个函数可以这样使用:

double a = 1.1;
double b = 1.2;
double d = 1.3;

一世)

...
double c1 = fun1(1.1, b, d); 

ii)

...
double c1 = fun1(a  , b, d);
// b has useful information here
// d has garbage

那就是第二个和第三个参数必须是左值,这很好。

b但是,参数和之间存在细微差别d。虽然b有用的信息d基本上被破坏了,但在函数调用之后使用它的值无论如何都是错误的。

这种情况让我想起了 C++11 中的 r 值引用和移动。移动的 r 值参数最终处于未指定但可分配的状态。这让我认为 C 中的 input-to-garbage 参数可以或多或少地映射到 r 值引用。

换句话说,包装器可以这样写来传达 , 的值d不仅会改变,而且会处于不可用状态。

double fun2(double const& a, double& b, double&& d){
    double c;
    Cfun(const_cast<double*>(&a), &b, &c, &d);
    return c;
}

这听起来合理吗,我是否通过定义这个包装器而失去了一些东西?类似的情况是否在类似的情况下实施?这是否证明了内置类型的 r 值(如double这里)?

d我发现的一个小问题是语法会变得更加冗长,尽管从函数调用后的可用性的角度来看更加清晰。

据我现在所见,可能的语法更改为:

一世)

...
//  double c = fun2(1.1, b, d); // now compile error, d is not a r-value
double c = fun2(1.1, b, std::move(d));  
// obvious error to use the value of d, since it was (probably) moved. However "moving a POD??"
d = 2.; // assignment is ok

ii)

...
double c = fun2(1.1, b, 1.3); // good, I can pass a literal now, nothing to misuse

iii)

...
double c = fun2(1.1, b, double{d}); // not clear, reaction "this seems a redudant cast"

iv)

...
double c = fun2(1.1, b, copy(d)); // verbose, but "d should be fine because it was copied"

在哪里template<class T> T copy(T&& t){return t;}

总之,比?fun2更好的包装器?Cfunfun1

如果double在上面的所有示例中都替换为具有 29 个成员变量(并且不想复制它们)的结构怎么办?

标签: cc++11refactoringlegacy-codeperfect-forwarding

解决方案


我的第一反应是 C 接口似乎采用指向任意(从接口中未知...)长度数组的指针,而当您创建 C++ 接口时,您似乎假设(知道??)所有参数实际上只是标量? 当然 - 如果确实如此,那就太好了。

如果所有参数确实是标量的概念是正确的,我会这样做:

double fun(double a, double& b, double d);

并完成。


推荐阅读