繁体   English   中英

定义 object 并在 function 参数中通过引用传递

[英]Define object and pass by reference inside function parameter

假设我们有一个名为foo的 function,它获取指向某个 object 的指针。

void foo(int *i){
    // Some code
}

我们可以通过以下方式调用这个 function:

int i;
foo(&i);

有没有办法我们可以在 c++ 的一行中制作上述代码片段? 就像是

foo(&int(4)) // This is invalid.

两个限制:

  1. foo更改为按引用接收不是一种选择。
  2. 我们还想避免使用像foo(new int(4))这样可能导致 memory 泄漏的东西。

“在一行中完成所有工作”通常是不可取的,因为它不会使代码更干净或更具可读性。 如果您必须声明一个int并获取其地址,那么您的代码会更好地明确表达这一点。

但是,封装常见任务的常用方法是函数:

 void foo_wrapper() {
       int i = 0;
       foo(&i);
 }

然后调用foo_wrapper()而不是foo(&i)

PS:房间里的大象是: foo显然将参数用作外参数,但您想忽略它。 如果这真的是foo应该使用的方式,那么它会做不必要的工作。 编写包装器隐藏了一个缺陷。 要解决实际问题foo必须进行修改。 我知道你说它是第三方库代码,但与其为库代码编写变通办法,我会重新考虑(a)它是否是正确的库,或者(b)也许我确实误解了它应该如何使用。

我不知道为什么需要这种行为,并假设这是某种“脑筋急转弯”问题。 如果这是“宏观魔术”的练习,可能会有更好的解决方案。

这是有效的:

#include <iostream>
#include <memory>

void f(int *x){
    ++(*x);
    std::cout << *x << '\n';
}
int main() {
     f(std::make_unique<int>(4).get()); 
    return 0;
}

预期 Output: 5

临时 object (类型为std::unique<int> )将在 function 调用之后被清理。 没有 memory 泄漏,但动态分配当然有开销。

&std::addressof被明确指定为不允许这样做,但如果你想忽略该安全措施,你可以定义你自己的std::addressof包装器,这将允许它:

template<typename T>
constexpr auto myaddressof(T&& t) noexcept {
    return std::addressof(t);
}

//...

// temporary created from argument to `addressof` lives
// until end of full-expression
foo(myaddressof(4));

不过这很容易出错。 例如,如果您将T&&替换为T ,那么使用它可能会导致未定义的行为。 这依赖于可能不直观的临时生命周期规则。 我真的不认为这比声明变量并将其与块中的调用一起包装更好。

完整的演示基于@JasonLiam的评论。

(请注意,您可能不应该使用addressof作为此 function 的名称。在某些极端情况下,如果调用不合格,依赖于参数的查找会导致该名称出现问题。)

void foo(int *i)表示参数的生命周期由调用者在foo之外管理。 这意味着在foo调用之前分配一些时间并在foo返回之后释放一些时间。 因此,由于您的原因#2,因此不可能有一个班轮。

处理可选指针值的惯用方式是使用nullptrNULL (C++11 之前)参数作为忽略它的指示符: foo(nullptr)

您可以使用包装器 class (在某种程度上类似于myaddressof function 模板的其他答案):

#include <iostream>

template<typename T>
class my_wrapper_class
{
  public:
    my_wrapper_class(T const &v) : value(v)
    {
    }
    T *operator&()
    {
      return(&value);
    }
    T const *operator&() const
    {
      return(&value);
    }
  private:
    T value;
};

void f(int *v)
{
  std::cout << "v: " << *v << std::endl;
  (*v)++;
}

int main()
{
  f(&my_wrapper_class<int>(4));
  return(0);
}

请注意,我读过的每本关于 C++ 的书都强烈建议不要重载一元运算符&我刚刚做过。 另一个选项(未显示)是将转换运算符定义为适当的指针并在调用站点省略显式&在我看来这同样令人困惑。

把它放在这里,以便有需要的人可以使用它并带有强烈的免责声明——不要那样做。 在朝这个方向前进之前,请考虑一下其他人在这个主题上的文章。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM