我有一个函数foo:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define X 3
#define Y 3
struct coords{
int a;
int b;
};
typedef struct coords cord;
// Print the array
char printArray(char row[][Y], size_t one, size_t two, struct coords cord)
{
row[cord.a][cord.b] = 'X';
// output column heads
printf("%s", " [0] [1] [2]");
// output the row in tabular format
for (size_t i = 0; i < one; ++i) {
printf("\nrow[%lu] ", i);
for (size_t j = 0; j < two; ++j) {
printf("%-5c", row[i][j]);
}
}
}
int moveUp(struct coords * cord);
int main(void)
{
struct coords cord;
char row[X][Y] =
{ { '-', '-', '-'},
{ '-', '-', '-'},
{ '-', '-', '-'} };
srand(time(NULL));
cord.a = (rand() % 3);
cord.b = (rand() % 3);
printf("\nValori rand: A %d, B %d\n", cord.a, cord.b);
// output the row
//printf("\nrobot:%c\n", robot);
puts("The array is:");
printf("\n");
printArray(row, X, Y, cord);
row[cord.a][cord.b] = '-';
//printArray(row, X, Y, &m, &n);
char h;
while(h != '3'){
switch (h) {
case 'N':
moveUp(&cord);
printArray(row, X, Y, cord);
row[cord.a][cord.b] = '-';
break;
}
scanf("%s", &h);
}
printf("\n");
}
int moveUp(struct coords * cord)
{
cord->a - 1;
if (cord->a == 2){
cord->a - 1;
} else if (cord->a == 1){
cord->a - 1;
} else if (cord->a == 0){
cord->a + 2;
}
/*
if (cord->a == 0) {
cord-> a = 2;
} else {
cord->a - 1;
}
*/
printf("\n A = %d, B = %d\n", cord->a, cord->b);
}
如果我像下面这样分配,它将做额外的复制吗?
std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
//
return result; <-- note there without std::move
}
我对第二种情况特别感兴趣,因为第一种情况是 编译器很可能知道将结果从foo()移动到v。
const auto v = foo(); <-- will it move the vector by default?
const auto &v = foo(); <-- same question as above, assuming T is movable
在这种情况下,foo()函数创建一个临时 result 。现在,由于v是参考,因此无法将结果移至v。因此,需要创建一个新副本。我的理解正确吗?
答案 0 :(得分:2)
通过应用as-if rule,允许编译器不改变程序可观察行为的所有代码转换。
但是,copy_elision是假设规则的例外:编译器可能会删除对move-和copy-constructor的调用以及对临时对象的析构函数的匹配的调用<即使这些呼叫有明显的副作用。要见证这些副作用,必须在编译时使用-fno-elide-constructors
选项。
在copy_elision页上,我们应查看以下子句:
在return语句中,当操作数是非易失性的名称时 具有自动存储期限的对象,此功能无效 参数或catch子句参数,并且属于同一类 类型(忽略cv-qualification)作为函数返回类型。这个 复制省略的变体称为NRVO,“命名为返回值 优化”。
简而言之,当编译器看到以下结构时,便知道它是NRVO的候选对象。
T FunctionName ( ... )
{
T a;
...
return a;
}
与您的问题的代码结构相匹配。
std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
return result;
}
您目睹的不是动作语义学,而只是NRVO。
因此,这些问题在这里没有任何意义。
const auto v = foo(); <-- will it move the vector by default?
const auto &v = foo(); <-- same question as above, assuming T is movable
T
是否可移动无关紧要。这里没有move
发生
我们也会在C ++ 11之前的编译器中获得相同的结果=> http://coliru.stacked-crooked.com/a/85c097f167b98b99
为更好地理解代码,请-
http://coliru.stacked-crooked.com/a/4b9a7e9504ab7aa8或cat /Archive2/4b/9a7e9504ab7aa8/main.cpp
在Coliru上。
然后添加-fno-elide-constructors
并查看详细分析。调用move构造函数时,您可能会在这里找到。
答案 1 :(得分:0)
从这link
来看,这两种情况似乎都没有多余的副本。