Kopya eleme, nesnelerin gereksiz kopyalanmasını / taşınmasını ortadan kaldıran bir derleyici optimizasyon tekniğidir.
Aşağıdaki durumlarda, bir derleyicinin kopyalama / taşıma işlemlerini atlamasına ve dolayısıyla ilişkili kurucuyu çağırmamasına izin verilir:
- NRVO (Adlandırılmış Dönüş Değeri Optimizasyonu) : Bir işlev değere göre bir sınıf türünü döndürüyorsa ve return ifadesinin ifadesi, otomatik depolama süresine (bir işlev parametresi olmayan) sahip kalıcı olmayan bir nesnenin adıysa , kopyala / taşı optimize edilmeyen bir derleyici tarafından gerçekleştirilecek olan atlanabilir. Öyleyse, döndürülen değer doğrudan işlevin dönüş değerinin başka türlü taşınacağı veya kopyalanacağı depolama alanında oluşturulur.
- RVO (Dönüş Değeri Optimizasyonu) : İşlev, naif bir derleyici tarafından hedefe taşınacak veya kopyalanacak isimsiz bir geçici nesne döndürürse, kopyalama veya taşıma 1'e göre atlanabilir.
#include <iostream>
using namespace std;
class ABC
{
public:
const char *a;
ABC()
{ cout<<"Constructor"<<endl; }
ABC(const char *ptr)
{ cout<<"Constructor"<<endl; }
ABC(ABC &obj)
{ cout<<"copy constructor"<<endl;}
ABC(ABC&& obj)
{ cout<<"Move constructor"<<endl; }
~ABC()
{ cout<<"Destructor"<<endl; }
};
ABC fun123()
{ ABC obj; return obj; }
ABC xyz123()
{ return ABC(); }
int main()
{
ABC abc;
ABC obj1(fun123());//NRVO
ABC obj2(xyz123());//NRVO
ABC xyz = "Stack Overflow";//RVO
return 0;
}
**Output without -fno-elide-constructors**
root@ajay-PC:/home/ajay/c++# ./a.out
Constructor
Constructor
Constructor
Constructor
Destructor
Destructor
Destructor
Destructor
**Output with -fno-elide-constructors**
root@ajay-PC:/home/ajay/c++# g++ -std=c++11 copy_elision.cpp -fno-elide-constructors
root@ajay-PC:/home/ajay/c++# ./a.out
Constructor
Constructor
Move constructor
Destructor
Move constructor
Destructor
Constructor
Move constructor
Destructor
Move constructor
Destructor
Constructor
Move constructor
Destructor
Destructor
Destructor
Destructor
Destructor
Kopya eleme gerçekleştiğinde ve kopyala / taşı-kurucu çağrılmasa bile, mevcut olmalı ve erişilebilir olmalıdır (hiç optimizasyon olmamış gibi), aksi takdirde program kötü biçimlendirilmiştir.
Bu tür kopya seçimine yalnızca yazılımınızın gözlemlenebilir davranışını etkilemeyeceği yerlerde izin vermelisiniz. Kopya seçimi, gözlemlenebilir yan etkilere (yani elide) izin verilen tek optimizasyon şeklidir. Misal:
#include <iostream>
int n = 0;
class ABC
{ public:
ABC(int) {}
ABC(const ABC& a) { ++n; } // the copy constructor has a visible side effect
}; // it modifies an object with static storage duration
int main()
{
ABC c1(21); // direct-initialization, calls C::C(42)
ABC c2 = ABC(21); // copy-initialization, calls C::C( C(42) )
std::cout << n << std::endl; // prints 0 if the copy was elided, 1 otherwise
return 0;
}
Output without -fno-elide-constructors
root@ajay-PC:/home/ayadav# g++ -std=c++11 copy_elision.cpp
root@ajay-PC:/home/ayadav# ./a.out
0
Output with -fno-elide-constructors
root@ajay-PC:/home/ayadav# g++ -std=c++11 copy_elision.cpp -fno-elide-constructors
root@ajay-PC:/home/ayadav# ./a.out
1
GCC, -fno-elide-constructors
kopya seçimini devre dışı bırakma seçeneği sunar. Olası kopya seçiminden kaçınmak istiyorsanız, kullanın -fno-elide-constructors
.
Artık neredeyse tüm derleyiciler, optimizasyon etkinleştirildiğinde (ve devre dışı bırakmak için başka bir seçenek ayarlanmadıysa) kopya seçimini sağlar.
Sonuç
Her kopya seçiminde, bir yapı ve kopyanın eşleşen bir imhası atlanır, böylece CPU zamanından tasarruf edilir ve bir nesne yaratılmaz, böylece yığın çerçevesinde yer tasarrufu sağlanır.