0

出于某种原因,我想返回 my::Vector 的一个对象(它基本上是一个在内部使用 STL 向量进行实际存储的包装类,并且确实提供了一些额外的功能)。我按值返回向量,因为函数每次都在本地创建一个向量。

my::Vector<int> calcOnCPU()
{
  my::Vector<int> v....
  return v;
} 

现在我可以有多个嵌套的函数调用(考虑到库设计),所以简而言之,如下所示:

my::Vector<int> calc()
{
    if(...)
      return calcOnCPU();
}

AFAIK,按值返回将调用 my::Vector 类的复制构造函数,它是:

Vector<int>::Vector(const Vector& c)
{
   ....
   m_vec = c.m_vec; // where m_vec is std::vector<int>
}

几个问题: 1)在复制构造函数中,它是否调用 std::vector 的复制构造函数?或赋值运算符,只是为了确认,std::vector 创建深层副本(意味着复制考虑基本整数类型的所有元素)。2) 在 calc() 中嵌套 calcOnCPU() 每个返回的向量 int: 2 或 1 个 Vector 副本会被创建吗?在这种简单的方法嵌套的情况下,如何避免多个副本?内联函数还是存在另一种方式?

更新 1:对我来说很明显,我需要保留自己的复制构造函数,因为有一些自定义要求。但是,我在 main 函数中做了一个简单的测试:

int main() {
   ...
   my::Vector v = calc();
   std::cout<<v;
}

我在复制构造函数中使用“std::cerr”打印了一些内容,以查看它何时被调用。有趣的是,对于上述程序,它甚至没有被调用一次(至少没有打印任何内容)。是复制省略优化吗?我在 Linux 上使用 GNU C++ 编译器 (g++) v4.6.3。

4

1 回答 1

2

在复制构造函数中,是否调用 std::vector 的复制构造函数?或赋值运算符

在您的情况下,它正在创建一个空的std::vector,然后复制分配它。使用初始化列表将直接复制构造它,这更简洁,可能更有效:

Vector<int>::Vector(const Vector& c) : m_vec(c.m_vec) {
    ....
}

只是为了确认, std::vector 创建深层副本

是的,复制 astd::vector将分配一个新的内存块并将所有元素复制到其中。

通过在 calc() 中嵌套 calcOnCPU() 每个返回的 int 向量:将创建 2 个或 1 个 Vector 副本?

这取决于编译器。它应该应用“返回值优化”(复制省略的特殊情况),在这种情况下,它不会创建本地对象并返回副本,而是会直接在为返回对象分配的空间中创建它。在某些情况下无法做到这一点 - 例如,如果您有多个 return 语句可能会返回几个本地对象之一。

此外,现代编译器还将支持移动语义,即使无法删除副本,向量的内容也会被移动到返回的对象而不是复制;也就是说,它们将通过设置向量的内部指针来快速传输,无需内存分配或元素复制。但是,由于您将向量包装在自己的类中,并且您已经声明了一个复制构造函数,因此您必须为该类提供一个移动构造函数才能使其工作 - 只有当您是使用 C++11。

在这种简单的方法嵌套的情况下,如何避免多个副本?内联函数还是存在另一种方式?

确保您的函数结构足够简单,以便复制省略工作。如果可以的话,给你的类一个移动向量的移动构造函数(或者删除复制构造函数,如果有赋值运算符,则允许隐式生成)。内联不太可能产生影响。

于 2012-07-06T13:05:08.240 回答