首页 文章

通过引用调用与指针参数[重复]

提问于
浏览
7

可能重复:FAQ:如何将对象传递给C中的函数?指针与参考

大家好,
在c / c中,我们可以通过引用传递对象或传递对象的指针 .
例如:
我想创建一个函数,它将字符串向量作为输入并输出一个包含每个字符串的值的映射 . 函数的返回值是bool,表示成功或失败 .

function (call by reference)

bool calculateSomeValue( vector<string> input, map<string, double>& result)
{
//// bla bla bla
return true/false;
}

function (using pointer )

bool calculateSomeValue( vector<string> input, map<string, double>* result)
{
//// bla bla bla
return true/false;
}

哪一个最好?有没有人知道这两种选择的利弊?

提前致谢 .

7 回答

  • 11

    这是一种风格问题 . 在谷歌(见Google C++ style guidelines),以下是首选:

    bool CalculateSomeValue(
        const vector<string>& input, map<string, double>* result);
    

    这是因为使用指针需要在调用站点显式使用&符号:

    CalculateSomeValue(input, &result);
    

    与使用引用类型调用它的方式相反:

    CalculateSomeValue(input, result);
    

    通过在参数被修改的情况下强制使用&符号,在呼叫站点清楚会发生什么 . 使用引用时,有必要查找每个函数的文档,以了解它是否有可能修改其输入参数 .

    但是,指针的使用也有其缺点 . 特别是,指针的使用意味着您将处理null的责任从指针被解除引用的调用者(如果该变量是指针而不仅仅是具有局部变量的表达式的地址)转移到函数 . 也就是说,当使用指针类型时, CalculateSomeValue 需要检查 nullptr (或者需要清楚地记录它需要在调用者中进行此检查),而使用引用类型是自我记录并清楚地表明非空参考是预期的 .

    对于这种特殊的情况,我个人强烈建议采用混合方法:

    bool CalculateSomeValue(
       const std::vector<std::string>& input,
       Output<map<string, double>> result);
    

    ...其中 Output<T> 由具有签名的函数创建:

    template<typename T> Output<T> WriteTo(T& output_ref);
    

    ...和 Output<T> 重载运算符 ->* 等 . 这基本上强制调用站点显式,因为输入将通过要求进行变异:

    CalculateSomeValue(input, WriteTo(result));
    

    ......而不是:

    CalculateSomeValue(input, result);
    

    ...同时获得引用的非null语义/语法 .

  • 1

    如果参数不是可选的,我发现许多开发人员更喜欢通过引用传递 . 然而,许多人喜欢仅通过指针传递视觉提示 . 这是c的一个延续,当程序增长以处理引用和指针的混合使用时,它会逐渐消失 .

    你可以假设引用不是null,但你不应该假设为指针 . 在这种情况下,你将不得不引入前提条件脚手架/检查,以确保上游的人不相信参数是可选的 - 如果你是防御性的 .

    就个人而言,我更喜欢通过引用传递,并使用描述性方法/函数/变量名称(如果您只详细说明标签,那么人们必须更频繁地访问文档) . 这样可以使程序的意图保持清晰,并避免额外的书面检查 . get*update* 可能比 calculate* 更明显 .

    使用引用是一致的,定义良好的,并且生成更简单的程序,因为您不处理混合变量/参数类型 .

    在这种情况下,它确实没有产生显着差异,只是 be consistent 在您的使用中 . 我使用的另一个提示是将修改后的参数放在同一个地方 . 具体来说,它们先于不断的争论 .

  • 0
    bool calculateSomeValue( vector<string> input, map<string, double>&* result)
    

    指针参考?这甚至都不会编译 . 第一个是正确的,只有正确的才是最好的!

    struct A {};
    
    void f(A & *a) {}
    

    编译给出rrror:

    prog.cpp:7:错误:无法声明指向'struct A&'的指针

    Ideone样本:http://www.ideone.com/8PJA5

  • 0

    你的第二个代码示例似乎是不正确的,因为你试图接受一个不应该编译的引用指针 .

    通过引用传递并传递指针同样有效(如果我错了,有人会纠正我,但我的理解是引用本质上是一个自动创建的指针然后被无缝解除引用),但建议通过引用传递,因为它更安全:

    • 您不能有空引用 .

    • 您无法更改引用的地址,而指针则允许您这样做 .

    有些人更喜欢显式指针语法,这清楚地表明它是一个指向传入对象的指针(因为你必须取消引用) .

  • 0

    最好的解决方案不存在 . 它来自案例案件 .

    例如,在某些情况下,接下来会更好:

    map<string, double> calculateSomeValue( const vector<string> &input )
    {
      map<string, double> res;
    // do something with input to form the output
      return res;
    }
    

    但是,如果可以的话,更喜欢使用标准算法

  • 0

    我假设第二个应该只是按点而不是指向引用的指针 .

    两者之间的决定只是风格和品味的问题 . 两条线的编译结果可能相同 .

    通常对于输出参数,C样式指南说它应该是指针 .

  • 0

    使用引用的唯一时间是实现需要它们的标准运算符 .

    但是,除此之外,指针应始终优先于任何应用方法的引用 .

    • 用户对象经常存储在指针中,智能或其他方式 . 当按需创建对象时,对始终有效的引用的约束太严格了 . 这使得参考参数不方便使用,因为需要进行笨拙的操作来传递该值 . referenceFunc( (*pObj) );

    • 通过引用传递是试图实施 Contract 范式的廉价替代品 . 哪个c不支持 .

    • 对该传递引用的所有(* somePtr)操作意味着你无论如何都会得到空指针调试,只是更加模糊,因为空指针看起来不像指针 .

    • 当程序员无法通过简单的检查判断某个函数的哪些参数可能会改变时,不要忘记维护问题 .

相关问题