这会做默认的移动操作吗

时间:2018-09-02 18:08:42

标签: c++ c++11 move

我有一个函数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。因此,需要创建一个新副本。我的理解正确吗?

2 个答案:

答案 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/4b9a7e9504ab7aa8cat /Archive2/4b/9a7e9504ab7aa8/main.cpp在Coliru上。
然后添加-fno-elide-constructors并查看详细分析。调用move构造函数时,您可能会在这里找到。

答案 1 :(得分:0)

从这link

来看,这两种情况似乎都没有多余的副本。