2012-07-06 99 views
0

出于某种原因,我想返回my :: Vector的对象(这基本上是一个包装类,内部使用STL向量用于实际存储,并提供一些额外的功能) 。随着函数每次在本地创建一个向量,我会按值返回向量。通过C++中的多重函数嵌套值返回向量

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

现在我可以有函数调用(考虑库设计)多重嵌套,因此,在短期类似如下:

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

据我所知,通过价值回归将调用我的::拷贝构造函数Vector类这是一件好事:

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

几个问题: 1)在拷贝构造函数,它被调用的std ::载体的拷贝构造函数?或赋值运算符,只需确认,std :: vector创建深度复制(意味着复制考虑基本整数类型的所有元素)。 2)在Calc()中嵌套calcOnCPU(),每个都返回int的Vector:2或1个Vector的拷贝将被创建?如果这种简单的方法嵌套,我怎么能避免多个副本?内联函数还是存在另一种方式?

UPDATE 1:对我来说很明显我需要保留我自己的拷贝构造函数,因为有一些自定义需求。但是,我做了一个简单的测试,主要功能:

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

我把一些印刷用我的拷贝构造函数“的std :: CERR”时看到它被调用。有趣的是,上面的程序甚至不会调用它(至少不会打印)。是否复制椭圆优化?我在Linux上使用GNU C++编译器(g ++)v4.6.3。

+0

即将推出的(当前?)C++标准中有“移动语义”。是的,STL向量执行深层复制,这就是你的代码 – fork0 2012-07-06 12:47:37

+0

[Rvalue引用和移动构造函数](http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors) – fork0 2012-07-06 12:49:07

+0

如果你试图摆脱临时副本,也许你可以让每个嵌套函数为你的向量引用一个引用参数,你修改... – 2012-07-06 12:51:04

回答

2

在拷贝构造函数中,它调用std :: vector的拷贝构造函数吗?或转让运营商

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

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

只是为了确认,性病::向量创建深拷贝

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

在calc()中嵌套calcOnCPU(),每个都返回int向量Vector:2或1个Vector的拷贝将被创建?

这取决于编译器。它应该应用“返回值优化”(复制elision的一个特例),在这种情况下,它不会创建一个本地对象并返回一个副本,但会直接在分配给返回的空间中创建它目的。例如,有些情况下无法完成 - 例如,如果有多个返回语句可能返回多个本地对象之一。

此外,一个现代编译器也将支持移动语义哪里,即使副本不能被消除,矢量的内容将被移动到返回的对象,而不是复制;也就是说,它们将通过设置向量的内部指针来快速传输,而不需要分配内存或复制元素。然而,既然你在自己的类中包装矢量,并且你已经声明了一个拷贝构造函数,那么你必须给这个类一个移动构造函数,以便它能够工作 - 只有当你使用C++ 11。

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

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

+0

感谢您的回答。一个关于“或删除复制构造函数以允许隐式生成”的说明“如果删除我的复制构造函数会发生什么?隐式生成的拷贝构造函数可以做什么不同? – usman 2012-07-06 13:11:18

+2

@ user600029:这不是隐式定义的复制构造函数可以做的事情,而是你在声明自己的时候禁止编译器执行的操作。特别是,如果可能,编译器(C++ 11)将提供一个移动构造函数,但如果您提供了一个拷贝构造函数(或赋值运算符...),它将不会这样做。也就是说,通过不提供禁止生成移动构造函数的操作之一,您可以免费获得性能提升(或者如果您仍在使用C++ 03,则更新编译器) – 2012-07-06 13:17:56

+0

@ user600029:如果您删除你的拷贝构造函数,然后隐式的将复制每个对象成员 - 在很多情况下,这正是你想要的。如果你删除它(和赋值运算符,并且不声明你自己的移动构造函数或移动赋值运算符),那么编译器也会给你一个移动构造函数。 – 2012-07-06 13:20:58