Рефакторинг функции ввода-вывода и уничтожения ввода в C ++ 11 - PullRequest
0 голосов
/ 21 декабря 2018

Мне нужно работать с парой устаревших 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 повышается до константной ссылки, bи d повышается до ссылки, а c повышается до возвращаемого значения.

Эта функция может использоваться следующим образом:

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

i)

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

ii)

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

То есть вторым и третьим аргументом должны быть l-значения, что нормально.

Однако между параметрами существует небольшая разница bи d.Хотя b имеет полезную информацию, d по существу уничтожен, и использование его значения после вызова функции будет ошибкой в ​​любом случае.

Эта ситуация напомнила мне ссылку на r-значение и перемещение в C ++11.Где перемещенные параметры r-значения оказываются в неопределенных, но назначаемых состояниях.Это заставляет меня думать, что параметр ввода в мусор в C может быть более или менее сопоставлен со ссылкой на 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 после вызова функции.

Насколько я сейчас вижу, возможные синтаксисы изменяются на:

i)

...
//  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 лучшая оболочка для Cfun, чем fun1?

Что если double будет заменен структурой с 29 переменными-членами (и не хотят копировать их) во всехпримеры выше?

1 Ответ

0 голосов
/ 21 декабря 2018

Моей первой реакцией было то, что интерфейс C, кажется, берет указатели на массивы произвольной (неизвестной из интерфейса ...) длины, тогда как при создании интерфейса C ++ вы, кажется, предполагаете (знаете ??), что все аргументы будут действительнотолько быть скалярами?Конечно, все хорошо, если это действительно так.

Если бы представление о том, что все аргументы действительно являются скалярами, верно, я бы просто сделал:

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

И покончим с.

...