Giriş
C++11'den önce move semantics adına yapılan işlem std::swap () kullanımıdır. emplace_back() için şöyle yapılırdı.
Örnek
Şöyle yaparız.
1. Madde Copy Constructor Varsa
Sınıfın copy constructor metodu varsa üretilmez.
Örnek
Copy constructor delete olarak işaretli olsa bile varmış gibi muamele görür.
Tüm bunları yazmak yerine resource, std::unique_ptr ile ile sarmalanabilir. Bu durumda bu 3 metodu yazmamız gerekmez yani, "Rule of Zero" kuralını uygulayabiliriz.
Elimizde move edilemeyen bir sınıf olsun.
Şu kod derlenmez.
Şöyle yaparız.
Move constructor deleted olarak işaretlense bile overload resolution için seçilmeyeceği anlamına gelmez, halen seçilebilir. Aynen header dosyasında imzası olan ancak cpp dosyasında kendisi olmayan metod gibidir.
Örnek
Şöyle yaparız.
Şöyle yaparız
C++11'den önce move semantics adına yapılan işlem std::swap () kullanımıdır. emplace_back() için şöyle yapılırdı.
class MyListOfVectors {
private:
//using `std::vector<int>` as an example of a "movable" type.
std::vector<std::vector<int>> list;
public:
void emplace_back(std::vector<int> &n) {
using std::swap;
list.push_back(std::vector<int>());
swap(list.back(), n);
//(possibly add something to rollback the `push`
// in case swap fails; to provide the strong
// exception guarantee)
}
};
pop_back() için şöyle yapılırdı.std::vector<int> MyListOfVectors::pop_back() {
using std::swap;
std::vector<int> r;
swap(list.back(), r);
list.pop_back();
return r; //Trust in copy elision to avoid any actual copies.
}
Nasıl TanımlanırÖrnek
Şöyle yaparız.
Foo (Foo&& other)
: _x(std::move(other._x))
{}
Örnek
Yanlış tanımlama ise şöyle.
Nasıl Çağrılır
Move constructor sağ taraf rvalue ise çağrılır. Eğer sağ taraf lvalue ise copy constructor çağrılır.
Örnekte copy constructor kullanılır.
Eğer move constructor çağrılmasını istiyorsak şöyle yaparız.Yanlış tanımlama ise şöyle.
Foo (const Foo &&other) {
...
}
Açıklaması şöyleYou cannot move from a const value because moving implies modifying what you're moving from.
Nasıl Çağrılır
Move constructor sağ taraf rvalue ise çağrılır. Eğer sağ taraf lvalue ise copy constructor çağrılır.
Örnekte copy constructor kullanılır.
A a;
A b = a;
b.foo();
A a("a");
A b = std::move(a);
b.foo();
Üretilme Koşulları
Şu koşullarda üretilmez.Aynı açıklama şöyleIf the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
- X does not have a user-declared copy constructor,
- X does not have a user-declared copy assignment operator,
- X does not have a user-declared move assignment operator,
- X does not have a user-declared destructor, and
- the move constructor would not be implicitly defined as deleted.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]
Şeklen şöyledir.The move constructor is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move constructor is valid (e.g. if it wouldn't need to assign constant members) (§12.8/10).
1. Madde Copy Constructor Varsa
Sınıfın copy constructor metodu varsa üretilmez.
Örnek
Copy constructor delete olarak işaretli olsa bile varmış gibi muamele görür.
class MyType {
public:
MyType(std::array<double, 6> a) {}
MyType(const MyType& that) = delete;
};
Örnek
Şu kod derlenmez.
Sınıfın move consructor metodu üretilmezse bile sınıf halen move edilebilir. Copy constructor metodunun olması yeterli. Şöyle yaparız.
4. Madde User Defined Destructor Varsa
Destructor yazmamızın sebebi "resource managing" bir sınıf olmamız. Resource yönetiyorsak zaten "move constructor", "move assignment oeprator" ve "destructor" metodlarını yazmamız gerekiyor.Şu kod derlenmez.
template <typename T>
struct Container
{
Container() = default;
Container(const Container& other) = delete;
Container(T* ptr) : ptr(ptr) {}
T* ptr;
~Container() { delete ptr; }
};
struct Foo { Foo(int a, int b) {} };
std::vector<Container<Foo>> myvector;
myvector.emplace_back((new Foo(1, 2))); //move constructor is not generated
ÖrnekSınıfın move consructor metodu üretilmezse bile sınıf halen move edilebilir. Copy constructor metodunun olması yeterli. Şöyle yaparız.
class Y{
public:
Y(){std::cout << "Default constructor\n";}
Y(const Y&) {std::cout << "Copy constructor\n";}
};
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};
int main(){
hasY hy;
hasY h=std::move(hy);
}
Çıktı olarak şunu alırız.Default constructorCopy constructor
4. Madde User Defined Destructor Varsa
Tüm bunları yazmak yerine resource, std::unique_ptr ile ile sarmalanabilir. Bu durumda bu 3 metodu yazmamız gerekmez yani, "Rule of Zero" kuralını uygulayabiliriz.
Örnek
Sınıfın destructor'ı varsa üretilmez.class Widget {
public:
~Widget(); // no move move functions
...
};
ÖrnekElimizde move edilemeyen bir sınıf olsun.
B b;
B b2 = std::move(b);
Şu hatayı alırız.invalid initialization of non-const reference of type 'B&' from an rvalue of type 'std::remove_reference<B&>::type {aka B}'
ÖrnekŞu kod derlenmez.
struct A{
std::unique_ptr<B> x;
virtual ~A() = default;
};
A f() {
A tmp;
return tmp;
}
Hata olarak şunu alırız.error: use of deleted function 'A::A(const A&)'
return tmp;
^~~
Açıklaması şöyle.virtual ~A() = default; is a user declared destructor. Because of that, A no longer has a move constructor. That means return tmp; can't move tmp and since tmp is not copyable, you get a compiler error.Düzeltmek için şöyle yaparız.
struct A{
std::unique_ptr<B> x;
A() = default; // you have to add this since the move constructor was added
A(A&&) = default; // defaulted move
virtual ~A() = default;
};
Default Move ConstructorŞöyle yaparız.
B(B&&) = default;
Bizim için noexcept() imzalı kod üretilir.B(B&&) noexcept {...};
Deleted Move ConstructorMove constructor deleted olarak işaretlense bile overload resolution için seçilmeyeceği anlamına gelmez, halen seçilebilir. Aynen header dosyasında imzası olan ancak cpp dosyasında kendisi olmayan metod gibidir.
Örnek
Şöyle yaparız.
class Boo
{
public:
Boo(){}
Boo(const Boo& boo) {};
Boo(Boo&& boo) = delete;
};
Boo TakeBoo()
{
Boo b;
return b;
}
Şöyle bir hata alırız.Örnekerror C2280: 'Boo::Boo(Boo &&)': attempting to reference a deleted function
Şöyle yaparız
#include <utility>
struct X
{
X() = default;
X(const X&) = default;
X(X&&) = delete;
};
int main()
{
X a;
X b(std::move(a));
}
Çıktı olarak şunu alırız.'X::X(X &&)': attempting to reference a deleted function
Hiç yorum yok:
Yorum Gönder