gpt4 book ai didi

c++ - 为什么没有为函数参数省略拷贝

转载 作者:太空狗 更新时间:2023-10-29 20:08:54 24 4
gpt4 key购买 nike

我有以下代码

#include <cstdlib>
#include <vector>
#include <chrono>
#include <iostream>

static const uint64_t BENCHMARK_RUNS(1000000);

std::vector<float> vec_mul_no_ref(const std::vector<float> x,
const std::vector<float> y) {
if(x.size() != y.size()) {
throw std::runtime_error("vectors are not the same size!");
}
std::vector<float> ans(x.size());
for (size_t ii=0; ii<x.size(); ii++) {
ans[ii] = x[ii] * y[ii];
}
return ans;
}

std::vector<float> vec_mul_ref_args(const std::vector<float>& x,
const std::vector<float>& y) {
if(x.size() != y.size()) {
throw std::runtime_error("vectors are not the same size!");
}
std::vector<float> ans(x.size());
for (size_t ii=0; ii<x.size(); ii++) {
ans[ii] = x[ii] * y[ii];
}
return ans;
}

void vec_mul_all_ref(const std::vector<float>& x,
const std::vector<float>& y, std::vector<float>& ans) {
if(x.size() != y.size() || y.size() != ans.size()) {
throw std::runtime_error("vectors are not the same size!");
}
for (size_t ii=0; ii<x.size(); ii++) {
ans[ii] = x[ii] * y[ii];
}
}

void bench_vec_mul() {
size_t vec_size(10000);
std::vector<float> x(vec_size);
std::vector<float> y(vec_size);
for(size_t ii=0; ii<vec_size; ii++) {
x[ii] = (static_cast<double>(rand()) / RAND_MAX) * 100.0;
y[ii] = (static_cast<double>(rand()) / RAND_MAX) * 100.0;
}
// bench no_ref
auto start = std::chrono::steady_clock::now();
for (uint64_t ii=0; ii < BENCHMARK_RUNS; ii++) {
std::vector<float> ans = vec_mul_no_ref(x, y);
}
auto end = std::chrono::steady_clock::now();
double time = static_cast<double>(
std::chrono::duration_cast<
std::chrono::microseconds>(end-start).count());
std::cout << "Time to multiply vectors (no_ref) = "
<< time / BENCHMARK_RUNS * 1e3 << " ns" << std::endl;

// bench ref_args
start = std::chrono::steady_clock::now();
for (uint64_t ii=0; ii < BENCHMARK_RUNS; ii++) {
std::vector<float> ans = vec_mul_ref_args(x, y);
}
end = std::chrono::steady_clock::now();
time = static_cast<double>(
std::chrono::duration_cast<
std::chrono::microseconds>(end-start).count());
std::cout << "Time to multiply vectors (ref_args) = "
<< time / BENCHMARK_RUNS * 1e3 << " ns" << std::endl;

// bench all_ref
start = std::chrono::steady_clock::now();
for (uint64_t ii=0; ii < BENCHMARK_RUNS; ii++) {
std::vector<float> ans(x.size());
vec_mul_all_ref(x, y, ans);
}
end = std::chrono::steady_clock::now();
time = static_cast<double>(
std::chrono::duration_cast<
std::chrono::microseconds>(end-start).count());
std::cout << "Time to multiply vectors (all_ref) = "
<< time / BENCHMARK_RUNS * 1e3 << " ns" << std::endl;
}

int main() {
bench_vec_mul();
return 0;
}

此代码在我的笔记本电脑上的示例输出(使用 g++ -o benchmark main.cc -std=c++17 -O3 编译)是:

Time to multiply vectors (no_ref) = 5117.05 ns                                      
Time to multiply vectors (ref_args) = 3000.69 ns
Time to multiply vectors (all_ref) = 2996.84 ns

第二次和第三次如此相似表明正在执行返回值优化并且正在省略该拷贝。我的问题是:为什么函数参数的拷贝也没有被编译器删除,以便第一次匹配后两个?将函数参数声明为 const 可确保它们不会更改,因此不会意外编辑原始变量。

我有 gcc (GCC) 8.1.1 20180531

最佳答案

My question is: why isn't the copy for the function arguments also elided by the compiler so that the first time matches the second two?

因为标准不允许。

省略不是偶然发生的事情;它不是无处不在的假设规则的一部分。因为它会影响用户可见的行为(复制/移动构造函数可能是用户定义的代码),所以标准必须明确说明有时,实现可以自由地不调用它们。因此,该标准在非常特定的情况下允许省略。

从参数表达式初始化参数时,仅当参数是值类型且参数表达式是该类型的临时值时才允许省略。好吧,如果您想获得技术知识,在 C++17 中,这种情况下没有省略:纯右值将直接初始化参数而不是显示一个临时参数,因此没有复制/移动要省略。

但这里不是这种情况。 xy 不是纯右值,因此不符合省略条件。它们将被复制到这些参数中。

确实,命名对象只有在您返回 时才有资格被省略。即便如此,如果它是该函数的参数,它也不起作用。

关于c++ - 为什么没有为函数参数省略拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51550073/

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