Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C++;11?_C++_C++11 - Fatal编程技术网

C++ 在C++;11?

C++ 在C++;11?,c++,c++11,C++,C++11,我有一些C++11之前的代码,其中我使用const引用来传递像vector这样的大参数。例如: int hd(const vector<int>& a) { return a[0]; } 例如,他说 C++11的移动语义使得按值传递和返回更具吸引力,即使对于复杂对象也是如此 上述两个选项在性能方面是否相同 如果是的话,什么时候使用选项1中的常量引用比选项2更好?(也就是说,为什么我们仍然需要在C++11中使用常量引用) 我提出这个问题的一个原因是,const引用使模板

我有一些C++11之前的代码,其中我使用
const
引用来传递像
vector
这样的大参数。例如:

int hd(const vector<int>& a) {
   return a[0];
}
例如,他说

C++11的移动语义使得按值传递和返回更具吸引力,即使对于复杂对象也是如此

上述两个选项在性能方面是否相同

如果是的话,什么时候使用选项1中的常量引用比选项2更好?(也就是说,为什么我们仍然需要在C++11中使用常量引用)


我提出这个问题的一个原因是,const引用使模板参数的推导变得复杂,如果在性能方面与const引用相同,那么只使用pass-by-value会容易得多。您将获得
向量的内部数组的副本,除非它即将消亡

int hd(vector<int> a) {
   //...
}
hd(func_returning_vector()); // internal array is "stolen" (move constructor is called)
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
hd(v); // internal array is copied (copy constructor is called)
int-hd(向量a){
//...
}
hd(func_返回向量());//内部数组“被盗”(调用移动构造函数)
向量v={1,2,3,4,5,6,7,8};
hd(v);//复制内部数组(调用复制构造函数)

C++11和右值引用的引入改变了关于返回向量之类的对象的规则——现在您可以这样做了(不必担心有保证的副本)。但是,关于将它们作为参数的基本规则没有改变——除非您确实需要一个真正的副本,否则您仍然应该通过const引用来获取它们。请记住,如果您没有传入r值,则通过值传递将导致完整的副本。因此,一般来说,按值传递可能会导致性能下降。

按值传递的一般经验法则是,您最终还是会制作一个副本。也就是说,与其这样做,不如:

void f(const std::vector<int>& x) {
    std::vector<int> y(x);
    // stuff
}
void f(const std::vector&x){
std::向量y(x);
//东西
}
如果您首先传递常量ref,然后复制它,则应改为:

void f(std::vector<int> x) {
    // work with x instead
}
void f(标准::向量x){
//改为使用x
}
这在C++03中部分是正确的,并且在移动语义中变得更加有用,因为当使用右值调用函数时,在pass by val情况下,副本可能会被移动替换


否则,当您只想读取数据时,通过
const
引用传递仍然是首选的有效方法。

您的示例有缺陷。C++11不会让您移动现有的代码,并且会复制一份

但是,您可以通过声明函数以获取右值引用,然后传递一个右值引用来获得移动:

int hd(vector<int>&& a) {
   return a[0];
}

// ...
std::vector<int> a = ...
int x = hd(std::move(a));
当然,您也可以将临时文件移入:

int hd(std::vector<int>&&); // Declaration of rvalue reference function
int x = hd({1,2,3,4});
inthd(std::vector&&);//右值引用函数的声明
int x=hd({1,2,3,4});
C++11的移动语义使得按值传递和返回更具吸引力,即使对于复杂对象也是如此

然而,您给出的样本是一个传递值样本

int hd(vector<int> a) {
考虑以下完整示例:

struct Str {
    char* m_ptr;
    Str() : m_ptr(nullptr) {}
    Str(const char* ptr) : m_ptr(strdup(ptr)) {}
    Str(const Str& rhs) : m_ptr(strdup(rhs.m_ptr)) {}
    Str(Str&& rhs) {
      if (&rhs != this) {
        m_ptr = rhs.m_ptr;
        rhs.m_ptr = nullptr;
      }
    }
    ~Str() {
      if (m_ptr) {
        printf("dtor: freeing %p\n", m_ptr)
        free(m_ptr);
        m_ptr = nullptr;
      }
    }
};

void hd(Str&& str) {
  printf("str.m_ptr = %p\n", str.m_ptr);
}

int main() {
  Str a("hello world"); // duplicates 'hello world'.
  Str b(a); // creates another copy
  hd(std::move(b)); // transfers authority for b to function hd.
  //hd(b); // compile error
  printf("after hd, b.m_ptr = %p\n", b.m_ptr); // it's been moved.
}
一般来说:

  • 传递普通对象的值
  • 如果目标需要可变副本,则按值传递
  • 按值传递如果您总是需要复制
  • 非平凡对象的Pass by const引用,其中查看器只需要查看内容/状态,但不需要对其进行修改
  • 当目标需要临时/构造值的可变副本时移动(例如
    std::Move(std::string(“a”)+std::string(“b”))
  • 当需要对象状态的局部性但希望保留现有值/数据并释放当前持有者时,移动

对于您所展示的示例,按值传递没有任何意义。通常,如果函数要生成本地副本,请按值传递参数。
const
references如何使模板参数的推导复杂化?>上述两个选项在性能方面是否相同?不可以。当客户端传入prvalue时,它们可以是相同的。但除此之外,成本是截然不同的。不要忘记常量正确性的重要性。如果函数不打算修改参数,则将其设为常量,如果是常量,则常量引用更有意义。否则,通过
const
reference传递参数不仅很好,而且更可取。强烈禁止将值传递给索引和元素。如果要传递移动语义,则应为
std::vector&&x
。@Samuel传递值可能会调用prvalues/xvalues上的移动构造函数和左值上的复制构造函数。因此,通过右值引用传递参数不会得到相同的语义。关于您的一般注意事项,我在不久前的某个地方读到,通过引用传递内置类型没有多大意义,因此,
const int&x
int x
没有多大意义,后者可以更快,因为复制这些类型比通过间接寻址更快。如果你有这方面的知识,你能说点什么吗?@luk32我也希望如此——大多数答案都集中在常量refs的“标准”应用上——但是完全独立的类型呢?类似于只包含基本体的结构。什么时候按值传递这个结构与按常量引用传递这个结构值得还是不值得?对象是否移动到函数中与参数是否声明为右值引用无关。如果它是临时的,编译器将把对象移动到参数中,或者完全删除副本(参见)a
绑定到右值引用,因此不能按照第一段代码的建议使用
a
调用code>。因此,使用
std::move(a)
实际上不仅仅是一个选项(“或将值强制转换为右值引用…”),如果只有
hd()
的声明,则必须使用它
int hd(vector<int> a) {
int hd(vector<int>&& a) {
std::vector<int> x;
x.push(1);
int n = hd(std::move(x));
std::cout << x.size() << '\n'; // not what it used to be
struct Str {
    char* m_ptr;
    Str() : m_ptr(nullptr) {}
    Str(const char* ptr) : m_ptr(strdup(ptr)) {}
    Str(const Str& rhs) : m_ptr(strdup(rhs.m_ptr)) {}
    Str(Str&& rhs) {
      if (&rhs != this) {
        m_ptr = rhs.m_ptr;
        rhs.m_ptr = nullptr;
      }
    }
    ~Str() {
      if (m_ptr) {
        printf("dtor: freeing %p\n", m_ptr)
        free(m_ptr);
        m_ptr = nullptr;
      }
    }
};

void hd(Str&& str) {
  printf("str.m_ptr = %p\n", str.m_ptr);
}

int main() {
  Str a("hello world"); // duplicates 'hello world'.
  Str b(a); // creates another copy
  hd(std::move(b)); // transfers authority for b to function hd.
  //hd(b); // compile error
  printf("after hd, b.m_ptr = %p\n", b.m_ptr); // it's been moved.
}