Named RVO Nedir?
Named RVO Copy Elision kuralının özel bir durumu. Bu kural sayesinde l-value bir nesne r-value bir nesneye dönüşür.
Named RVO Copy Elision kuralının özel bir durumu. Bu kural sayesinde l-value bir nesne r-value bir nesneye dönüşür.
CopyElision ve onun alt kümesi olan NRVO C++11 ve C++14 ile mecburi değil ancak C++17 ile mecburi hale geliyor.
NRVO'nun Etkisi Nedir?
NRVO uygulanırsa return edilen nesnenin copy/move constructor metodu çağrılmaz. Constructor çağrılmadığı için destructor'ı varsa o da çağrılmaz. Bu durum şaşırtıcı sonuçlara sebep olabiliyor. Açıklaması şöyle
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.
Örnek
NRVO'nun olduğunu görmek için şöyle bir kod olsun.
Copy constructor veya move constructor, destructor metodları copy elision sayesinde çağrılmaz.
Copy constructor metodu olmayan bir nesne olan unique_ptr kullanan bu kod, copy elision sayesinde derlenir.
Örnek
std::vector<int> foo() {
int i;
std::vector<int> a(100);
printf("%p, %p, %p\n", &i, &a, &(a[0]));
return a;
}
int main() {
int i;
std::vector<int> b = foo();
printf("%p, %p, %p\n", &i, &b, &(b[0]));
}
Çalıştırmak için şöyle yaparız. Hem foo() metodundaki hem de main() metodundaki std::vector nesnesinin adresi aynıdır.$ vim main.cpp
$ cc -std=c++11 -lc++ main.cpp
$ ./a.out
0x7ffee28d28ac, 0x7ffee28d28f0, 0x7ff401402c00
0x7ffee28d290c, 0x7ffee28d28f0, 0x7ff401402c00
$
std::stringCopy constructor veya move constructor, destructor metodları copy elision sayesinde çağrılmaz.
std::string system_call(const char *cmd){
std::string a;
...
return a;
}
std::string st = system_call("whatever code"); //system_call metoduna direkt st geçilir
std::unique_ptrCopy constructor metodu olmayan bir nesne olan unique_ptr kullanan bu kod, copy elision sayesinde derlenir.
#include <iostream>
#include <memory>
using namespace std;
unique_ptr<int> foo()
{
unique_ptr<int> p( new int(10) );
return p; // 1
//return move( p ); // 2
}
int main()
{
unique_ptr<int> p = foo();
cout << *p << endl;
return 0;
}
std::vectorÖrnek
Şöyle yaparız.
Örnek
Şöyle yaparız. Copy constructor delete olduğu halde derlenir
Şöyle yaparız. Copy constructor ve destructor çalışmaz
std::vector<huge_thing> foo()
{
std::vector<huge_thing> result{/* ... */};
return result;
}
void bar()
{
auto v = foo(); // (0)
}
Kendi SınıfımÖrnek
Şöyle yaparız. Copy constructor delete olduğu halde derlenir
struct Foo {
Foo() = default;
Foo(const Foo&) = delete;
};
int main() {
// Works in C++17 and C++20, fails in C++14 and before
Foo foo = Foo();
}
ÖrnekŞöyle yaparız. Copy constructor ve destructor çalışmaz
struct Foo {
Foo() { std::cout << "Constructed" << std::endl; }
Foo(const Foo &) { std::cout << "Copy-constructed" << std::endl; }
Foo(Foo &&) { std::cout << "Move-constructed" << std::endl; }
~Foo() { std::cout << "Destructed" << std::endl; }
};
Foo foo() {
Foo mystr;
return mystr;
}
int main() {
Foo result = foo();
}
Örnek
Şöyle yaparız. Burada NRVO uygulanırsa Foo sınıfının destructor metodu çalışmaz. Bu durumda main metodunun çıktısı 0 olur
// Foo adds an element to a std::vector passed by reference
// on construction in the destructor
struct Foo {
Foo(std::vector<double>& v) : m_v(v){
}
~Foo(){
m_v.push_back(1.0);
}
std::vector<double>& m_v;
};
std::vector<double> bar(){
std::vector<double> ret;
Foo foo(ret);
return ret;
}
int main(){
std::cout << bar().size() << "\n";
}
Hiç yorum yok:
Yorum Gönder