具有价值语义的表现

Ins*_*oop 11 c++ move c++11

我非常关注代码的性能和可读性,我从Google的Chandler Carruth那里得到了我的大部分想法.我想在不丢失性能的情况下为C++应用以下规则来实现干净的代码.

  • 将所有内置类型作为值传递
  • 传递所有不想通过const引用变异的对象
  • 传递函数需要按值消耗的所有对象
  • 禁止其他一切.在拐角情况下,传递指针.

这样,功能没有副作用.这是代码可读性的必要条件,并使C++成为一种功能.现在来了表现.如果你想编写一个为std :: vector的每个元素添加1的函数,你能做什么?这是我的解决方案.

std::vector<int> add_one(std::vector<int> v) {
    for (std::size_t k = 0; k < v.size(); ++k) {
        v[k] += 1;
    }
    return v;
}

...
v = add_one(std::move(v));
...
Run Code Online (Sandbox Code Playgroud)

我发现这非常优雅,只有2个动作.这是我的问题:

  • 这是合法的C++ 11吗?
  • 你认为这个设计有什么缺点吗?
  • 编译器无法自动将v = f(v)转换为此?一种复制省略.

PS:人们问我为什么不喜欢通过参考.我有两个参数:

1 - 它没有在调用站点明确指出哪个参数可能会发生变异.

2 - 它有时会扼杀性能.由于别名,引用和指针是编译器的地狱.我们来看下面的代码

std::array<double, 2> fval(const std::array<double, 2>& v) {
    std::array<double, 2> ans;
    ans[0] = cos(v[0] + v[1]);
    ans[1] = sin(v[0] + v[1]);
    return ans;
}
Run Code Online (Sandbox Code Playgroud)

将ans作为参考的相同代码慢了2倍:

std::array<double, 2> fref(const std::array<double, 2>& v,
        std::array<double, 2>& ans) {
    ans[0] = cos(v[0] + v[1]);
    ans[1] = sin(v[0] + v[1]);
}
Run Code Online (Sandbox Code Playgroud)

指针别名可防止编译器使用单个机器指令计算sin和cos(Gcc目前不进行优化,但icpc使用值语义进行优化).

Mar*_*k B 3

对我来说,它似乎是合法的 C++11。缺点可能是基于意见的,所以我不会解决这个问题,但至于你的第三点,编译器只有在可以证明该函数不会以v任何方式别名的情况下才能进行该转换。由于这样的编译器编写者可能不会选择对简单情况实现这样的优化,他们可以分析并将这种负担(无别名)留给程序员。

但也要考虑:当函数拒绝以具有明显性能特征的清晰版本编写时,也许您正在编写错误的函数。相反,编写一个像标准库一样在一定范围内运行的算法,问题就会消失:

template <typename Iterator>
void add_one(Iterator first, Iterator last)
{
    for(; first != last; ++first)
    {
        (*first) += 1;
    }
}
Run Code Online (Sandbox Code Playgroud)