I have been hearing about this, very advertised way of implementing an assign operator=() in C++.
EDIT: MVP(s),
- https://onlinegdb.com/meN5a_I2I (Version 1)
- https://onlinegdb.com/HybpyOO6P (Version 2)
Version 2:
a.out: main.cpp:52: int main(): Assertion `ptr == a.data()' failed.
Aborted (core dumped)
Here's where it seems to fail,
A copy operator=() without Copy & Swap Idiom:
Data& operator=(const Data& rhs)
{
if(this != &data)
{
_size = rhs.size();
delete[] local_data;
local_data = new char[_size];
std::copy(rhs.data(), rhs.data() + rhs.size(), local_data);
}
return *this;
}
Main.cpp with above (non-swap idiom) implementation called,
int main(){ Data a("Some data"); auto ptr = a.data(); // Obtains a pointer to the original location a = Data("New data"); // When a is modified, this modification should effect the 'ptr' assert(ptr == a.data()); // Succeeds return 0; }
Same as above, except with Copy & Swap Idiom:
void swap(Data& rhs) noexcept
{
std::swap(_size, rhs.size());
std::swap(local_data, rhs.data());
}
Data& operator=(const Data& rhs)
{
Data tmp(data);
swap(data);
return *this;
}
2: With swap idiom implementation:
int main(){
Data a("Some data");
auto ptr = a.data(); // Obtains a pointer to the original location
a = Data("New data"); // When a is modified, this modification should effect the 'ptr'
assert(ptr == a.data()); // Fail
return 0;
}
I observe, that there's clean up. But, is the clean and easy implementation of Copy & Swap Idiom supposed to fail here. And, I know that some runtime overhead does occur. But, generally, the Copy & Swap idiom seems a lot cleaner and better.
EDIT: I am aware of the self-assignment problem, and that this is supposed to help with that. Self-assignment is exceedingly rare in most programs, so an explicit check adds a small cost to every self-assignment even though the check is almost always false.
Sutter & Alexandrescu shows an assignment operator written in terms of a swap member. This is safe against self-assignment, exception-safe, and re-uses the copy constructor.
Full code for version 2:
#include <iostream>
#include <cassert>
using namespace std;
class Data
{
private:
char* local_data;
int _size = 0;
inline int length(const char* str)
{
int n = 0;
while(str[++n] != '\0');
return n;
}
public:
Data() {
local_data = new char[_size];
}
Data(const char* cdata) : _size { length(cdata) }{
local_data = new char[_size];
std::copy(cdata, cdata + _size, local_data);
}
int size() const { return _size; }
const char* data() const { return local_data; }
void swap(Data& rhs) noexcept
{
std::swap(_size, rhs._size);
std::swap(local_data, rhs.local_data);
}
Data& operator=(const Data& data)
{
Data tmp(data);
swap(tmp);
return *this;
}
};
int main()
{
Data a("Some data");
auto ptr = a.data(); // Obtains a pointer to the original location
a = Data("New data"); // When a is modified, this modification should effect the 'ptr' (char*)
assert(ptr == a.data()); // Fails
return 0;
}