gpt4 book ai didi

d - 我如何知道何时使用 `const ref`或 `in`?

转载 作者:行者123 更新时间:2023-12-04 14:42:00 25 4
gpt4 key购买 nike

void foo(T, size_t size)(in T[size] data){...}
//vs
void foo(T, size_t size)(const ref T[size] data){...}

根据 https://stackoverflow.com/a/271344/944430的说法,在某些情况下,在C++中 pass by value可能会更快。

但是D有一个特殊的关键字 in,我想知道何时应该使用它。 in是否总是产生副本,还是编译器优化?

有什么指南可以帮助我在 const refin之间做出选择?

最佳答案

我认为您永远不要在函数参数上使用inin是D1中的工件,可以减少代码损坏,但已更改为等效于const scope。因此,每次您想到在函数参数上键入in时,都请想到const scope,因为这就是您真正在做的事情。而且scope当前仅对委托(delegate)执行任何操作,在这种情况下,它告诉编译器接受委托(delegate)的函数不会返回它或将其分配给任何东西,因此不必分配任何闭包来保存该委托(delegate)的状态。 (因此,在很多情况下,它可以提高代表的效率),而对于所有其他类型,则完全被忽略,这意味着使用它是没有意义的(并且可能会造成混淆),并且对于其他类型,它的确意味着其他含义(例如,有人建议应强制以scope形式传入的指针不能转义该函数),然后代码的语义可能会以意想不到的方式改变。大概会在发生这种情况时伴随适当的警告,但是为什么要用无意义的属性标记您的代码,而该属性以后可能会有意义,从而迫使您更改代码?在这一点上,scope仅应在委托(delegate)上使用,因此in仅应在委托(delegate)上使用,并且您通常不希望const委托(delegate)。因此,只是不要使用in

因此,最终,您真正要问的是应该使用const还是const ref

简短的答案是,除非您想更改传入的参数,否则通常不应该使用ref。我还要指出,此问题对除结构和静态数组之外的其他任何东西都没有意义,因为类已经是引用类型,并且没有任何内置类型(保存为静态数组)会花费很多东西来复制。更长的答案是...

移动语义内置于D中,因此,如果您有一个按值接受其参数的函数-例如

auto foo(Bar bar) { ... }

然后它将移动参数(如果可以的话)。如果您将其传递给左值(可以在赋值左侧的值),则该值将被复制,除非在编译器能够确定它可以优化复制后的情况下(例如,当在该函数调用之后从未使用过变量时,但这将取决于所使用的编译器和编译器标志。因此,按值将变量传递给函数通常会得到一个副本。但是,如果向函数传递右值(不能在赋值左侧显示的值),则它将移动该对象而不是复制该对象。这不同于C++,后者直到C++ 11才引入移动语义,即使这样,它们也需要移动构造函数,而D使用poSTLbit构造函数,后者会对其进行更改,以便可以默认进行移动。关于此的先前的几个SO问题:

Does D have something akin to C++0x's move semantics?
Questions about postblit and move semantics

因此,是的,在D中,通过 ref传递将避免复制,但在D中, ref始终需要一个左值(即使使用 const)。因此,如果像在C++中一样将 ref const(T)放到任何地方,那么您将有很多真正令人讨厌的函数调用,因为每个临时变量都必须首先分配给变量才能调用该函数。因此,您应该认真考虑仅在想要突变传入的变量时才使用 const T&,而不是为了提高效率。当然,您的默认设置应该是不通过 ref传递,但是如果您确实需要这种额外的效率,则有两种选择:
  • 重载const ref -ness上的函数,以便您拥有一个由ref承担的重载,以及一个由const ref承担的重载,以便将左值传递给一个重载而无需复制,而右值传递给另一个,而无需外部变量。例如

  •     auto foo(const Bar bar) { foo(bar); }
    auto foo(ref const(Bar) bar) { ... }

    这有点烦人,但当您只有 ref一个参数时,效果很好。但是,随着添加更多的 ref参数,您将获得过载的组合爆炸式增长。例如

        auto foo(const Bar bar, const Glop glop) { foo(bar, glop); }
    auto foo(ref const(Bar) bar, const Glop glop) { foo(bar, glop); }
    auto foo(const Bar bar, ref const(Glop) glop) { foo(bar, glop); }
    auto foo(ref const(Bar) bar, ref const(Glop) glop) { ... }

    因此,这在一定程度上可行,但并不是特别令人愉快。而且,如果像我在这里那样定义重载,那么它也有一个缺点,即右值最终会传递给包装函数(添加了一个额外的函数调用,尽管该调用应该相当可移植),这意味着它们是现在由 ref传递给主重载,并且如果这些参数之一传递给另一个函数或返回,则编译器无法执行移动,而如果未涉及 ref,则它可以这样做。这就是现在有人争辩说您不应该像在C++ 98中那样在C++ 11中大量使用 ref的原因之一。

    您可以通过为每个重载复制函数体来解决该问题,但这显然会导致维护问题以及代码膨胀。
  • 替代方法是使用const T&,基本上可以为您完成此操作,但是必须对函数进行模板化。例如

  •     auto foo()(const auto ref Bar bar, const auto ref Glop glop) { ... }

    因此,现在您只有一个重载,但是每次使用 auto ref -ness的不同组合实例化模板时,它仍然会在引擎盖下生成所有这些重载,并带有完整的代码。因此,您的代码更简洁,但是您仍然会感到肿,如果您需要使用虚拟函数来执行此操作,那么您就不走运了,必须返回到更明确的重载解决方案,因为模板化函数可以是虚拟的。

    因此,总的来说,由于效率原因,试图让您的函数接受 ref变得很丑陋。 D内置了移动语义的事实减少了对它的需求(就像C++ 11一样,现在有人争论说,由于移动语义以及编译器如何对其进行优化,按值传递通常更好。在一般情况下,在D中执行此操作很丑陋,除非您真正获得了重要的性能提升,否则仅出于效率考虑就不值得通过 const ref传递。除非您实际测量了值得付出痛苦的性能差异,否则您可能应该避免使用 ref来提高效率。

    要考虑的另一件事-与 ref -ness分开-是D的 ref比C++的 const严格得多(例如,丢弃 const和mutation是D中未定义的行为,而D的 const是可传递的)。因此,在各处拍打 const有时会引起问题-尤其是在通用代码中。因此,使用它可以很好地防止意外突变或表明函数不会改变其参数,但不要仅仅在不应该像C++那样对变量进行突变的地方随意地涂抹它。在合理的地方使用它,但是要注意,即使C++的 const可以工作,您也会遇到D的 const过于严格而无法使用的情况。

    因此,在大多数情况下,当您希望函数采用 const时,应默认使用简单的 T。然后,如果您知道效率是一个问题,则可以考虑使用某种形式的 T(如果不处理虚拟函数,则可能更喜欢 refauto ref)。但默认为不使用 const auto ref。这样,您的生活将会更加愉快。

    关于d - 我如何知道何时使用 `const ref`或 `in`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35974858/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com