2014-10-09 35 views
9

C++ derleyiciler sanal işlevler için RVO uygulayabilir mi? Bu durumdaSanal bir işlev RVO'ya (dönüş değeri optimizasyonu) bir aday olabilir mi?

:

class AbstractReader 
{ 
//... 
public: 
    virtual std::vector<float> getFloatVector() = 0; 
//... 
} 

class XmlReader : public AbstractReader 
{ 
//... 
public: 
    virtual std::vector<float> getFloatVector() 
    { 
     std::vector<float> result; 

     //Do some parsing here... 

     return result; 
    } 
//... 
} 



class BinaryReader : public AbstractReader 
{ 
//... 
public: 
    virtual std::vector<float> getFloatVector() 
    { 
     std::vector<float> result; 

     //Do some decoding here... 

     return result; 
    } 
//... 
} 

RVO return result; hatlarına başvurabilir miyim? Tahmin etmem.

Daha sonra, bu durumda büyük kapları iade etmenin yolu olan std::move(result) mu?

Teşekkür

+1

Sorunuzu açıklar mısınız? Sık sık sanal işlevler mi veriyorsunuz? – juanchopanza

+1

@juanchopanza: Bence, RVO'nun sanal bir işleve geri dönüp dönmeyeceğini, sanal bir işlevin döndürülmesiyle ilgili bir sanal işlev, yani sanal işlevin geri dönebileceği herşeyin çalışıp çalışmadığını düşünüyorum. (Ve bunun prensipte işe yaramaması için bir neden göremiyorum) – Damon

+0

@Damon Aynı şeyi düşünüyorum, ancak OP'nin sormak istediklerini açıklamasına izin verin. – juanchopanza

cevap

4

Evet, derleyici RVO gerçekleştirebilir zorla Yani bile. Bazı testler kodu pişmiş ve godbolt aracılığıyla ran:

struct M { 
    M(); 
    M(const M&); 
    M(M &&); 
    ~M(); 
    double * ptr; 
}; 

M getM(); 

struct A { 
    virtual M foo() = 0; 
}; 

struct B : A { 
    virtual M foo() override; 
}; 

M B::foo(){ 
    M m; 
    return m; 
} 

struct C : B { 
    virtual M foo() override; 
}; 
M C::foo(){ 
    M m = getM(); 
    return m; 
} 

A* getA(); 

int main(){ 
    A* p = getA(); 
    M m = p->foo(); 
} 

g++ -O3 kopyasına herhangi çağrıyı demontaj gelen Dikkat çekici devamsızlık

B::foo(): 
    pushq %rbx 
    movq %rdi, %rbx 
    call M::M() 
    movq %rbx, %rax 
    popq %rbx 
    ret 
C::foo(): 
    pushq %rbx 
    movq %rdi, %rbx 
    call getM() 
    movq %rbx, %rax 
    popq %rbx 
    ret 
main: 
    subq $24, %rsp 
    call getA() 
    movq (%rax), %rdx 
    movq %rax, %rsi 
    movq %rsp, %rdi 
    call *(%rdx) 
    movq %rsp, %rdi 
    call M::~M() 
    xorl %eax, %eax 
    addq $24, %rsp 
    ret 

üreten veya M yapıcısı taşıyın. Ayrıca

, kopya elision kriterlerini belirleyen standardın paragraf sanal ve nonvirtual üye fonksiyonları arasında bir ayırım ve kopya elision için standart karşılandığında, return açıklamada "için aşırı yük çözünürlüğü ilk Nesne bir rengin ile atanmış gibi gerçekleştirildi.

kopya elision sebebi ne olursa olsun gerçekleşemez ve bir hareket yapıcı varsa, return m; hep kopya kurucu yerine hareket yapıcısı çağıracağı

M foo() { 
    M m = /*...*/; 
    return m; 
} 

bir işlevde, demek ki

. Bu nedenle, yerel bir değişken döndürüyorsanız, return deyimi için std::move kullanmanıza gerek yoktur.

+0

Mükemmel cevap, açık ve ayrıntılı. – galinette

0

Eğer return std::move(result); varsa, hiçbir şey elde edemeyiz ve kaybedebilir. Öyleyse yapma.

Hiçbir şey elde edemez, standart açıkça diyor çünkü RVO şartlar yerine getirildiği veya bir parametreyi dönen eğer", rvalue olarak dönen deneyin o derlemek olmaz ancak ve ancak, lvalue olarak geri ilk. Eğer return result;, derleyici aksi kullanılmaktaymış özellikle RVO önler return std::move(result); ilk.

sen kaybedebilir, return std::move(result); beri denemek için.

+0

Aslında, RVO'nun mümkün olmadığı durumlarda ve döndürülen tip hareketliyse ve altta yatan büyük bir tampon varsa, çok fazla kazanabilirsiniz. Bu aynı zamanda sorunun cevabı değildir. – galinette

+2

@galinette Hayır, kopya seçimi herhangi bir nedenden dolayı gerçekleştirilemezse, 'return sonucu;' mümkün olduğunda bir hamle yapmaya devam edecektir. –

+0

@galinette Eğer RVO mümkün değilse, o zaman 'sonuç' ne yerel bir değişken, ne de fonksiyonun bir parametresidir, bu yüzden' std :: move' kullanmak bu durumda zaten bir no-brainer değildir. RVO hakkında soru soruyordunuz, bu yüzden RVO kriterlerinin karşılandığı bir durumla karşılaştım. – Angew