I have an object constructor that takes in a const pointer to a const object
A::A( const B* const ex): m_B(B){};
where m_B:
const B* const m_B;
I am now trying to create a copy constructor and assignment operator
I have tried the following without any luck.
Copy Constructor:
A::A( const A& cpy): *m_B(*cpy.m_B) {}
This does not work...how do I approach this?
Assignment Operator:
A& A::operator=(const A& rhs) {
*m_B = *rhs.m_B // I know this won't work because const cannot be assigned
// error: assignment of read-only data-member
}
Any ideas how to solve this problem?
If you want deep copies anyways, why do you have a pointer? Just have a raw object.
class B{
// ...
};
class A{
const B _b;
public:
A(A const& other)
: _b(other._b) {}
private:
// no assignment operator, since const objects can't be reassigned
A& operator=(A const&); // undefined
};
Your problem is, constructors don't have the return value.
And assignment operator is operator=, not operator().
In your constructor, you took a pointer and saved pointer, not the contents of object the pointer points to. If you take this semantics, you should only copy pointers instead of copying the content: (Or do you have something else to achieve?)
class B;
class A {
public:
const B* m_b;
A( const B* const ex): m_B(ex){};
//copy constructor
A(const A& cpy): m_B(cpy.m_B){};
//assignment operator
A& operator=(const A&cpy) {m_B = cpy.m_B;};
};
The assignment operator might have to create a new instance with new:
A& A::operator=(const A& rhs) {
m_B = new B(rhs.m_B);
return *this;
}
Of course, you have to keep track of this, so you can delete the pointer if you allocate it. If you don't want to keep track, use new in the constructor as well.
Or even better, use the new shared_ptr to not have to care about pointers much at all.
The "placement new" operator can be useful when assigning objects that have const pointers.
class ref
{
public:
// Normal constructor creates new immutable reference.
ref(const char* const ptr, size_t len): m_ptr(ptr),m_len(len) {}
// Copy constructor creates new copy of existing immutable reference.
ref(const ref& o): m_ptr(o.m_ptr),m_len(o.m_len) {}
// Assignment operator replaces existing immutable reference with another one.
// Previous reference is gone.
ref& operator=(const ref& o) { new (this) ref(o.m_ptr, o.m_len); return *this; }
private:
const char* const m_ptr;
size_t m_len;
}
Related
first, my code:
struct A {
A(int size);
~A();
A(A&& other);
A& operator=(const A& other);
uint8_t* data = nullptr;
};
A::A(int size)
{
data = new uint8_t[size];
}
A::~A()
{
delete [] data;
data = nullptr;
}
A::A(TPixel &&other)
{
data = other.data;
}
A& A::operator=(const A& other)
{
data = other.data;
}
I have two variable
std::shared_ptr<A> a = std::make_shared<A>(5);
std::shared_ptr<A> b = std::make_shared<A>(5);
I tried std::swap(a, b);
and found error in valgrind:
std::enable_if<std::__and_<std::is_move_constructible<A*>, std::is_move_assignable<A*> >::value, void>::type std::swap<A*>(A*&, A*&)
Why I get this error?
I have implemented move operators and when I tested std::is_move_assignable and std::is_move_constructible the return value was true.
found error in valgrind:
std::enable_if<std::__and_<std::is_move_constructible<A*>, std::is_move_assignable<A*> >::value, void>::type std::swap<A*>(A*&, A*&)
Why I get this error?
What you show is not an error. It is a function declaration.
I have implemented move operators
You have not implemented a move assignment operator.
P.S.
You haven't defined the move constructor.
You have defined a constructor that you didn't declare: A::A(TPixel &&). This may be related.
The copy assignment operator
leaks memory.
leaves both objects pointing to the same array.
The destructor has undefined behaviour if the object has been copy-assigned and the copy has already been destroyed.
I read that we can use in case member pointer to function or array.
How I can write copy constructor and copy assignment if I have member type pointer to function or pointer to array.
class test {
public:
test(const test& other) {
// code
}
test& operator=(const test& other) {
if (this != &other) {
// code
}
return *this;
}
private:
int (*fnc_ptr)(int, int);
int (*arr_ptr)[2];
};
As title, can be to overloading operator = for casting?
I have a simple class.
class A{
protected:
int m_int;
public:
A& operator=( int& obj)
{
m_int = obj;
return *this;
}
};
I want:
A t_a = 1;
and
int t_int = t_a;
Is there a way to do this?
Just define conversion operator
operator int() const
{
return m_int;
}
or
explicit operator int() const
{
return m_int;
}
In the last case you have to use an explicit casting in the statement
int t_int = int( t_a );
Take into account that the assignment operator should be declared like
A& operator=( const int& obj)
{
m_int = obj;
return *this;
}
or like
A& operator=( int obj)
{
m_int = obj;
return *this;
}
Otherwise it will be impossible to bind the non-constant reference with integer literals or temporary values.
As for the assignment operator then you may define only a compound assignment operator for the type int and the type A.
For example you could define the operator += or something other operator.
Yes, that’s possible. You need a custom ctor and assignment operator. But writing those disables some of the compiler generated ctors/assignment ops. If you still need/want them, you need to reintroduce them explicitly.
class A
{
protected:
// Note the initializer. Without it m_int is uninitialized
// when you default construct an A. That’s a common source
// of bugs.
int m_int = 0;
public:
// Following two are the important ones
A(int i) : m_int(i) {}
A& operator=(int i)
{
m_int = i;
return *this;
}
// if A needs to be default constructible as well
A() = default;
// The int ctor/assignment disable the compiler generated
// normal copy ctor/assignment (the ones that take another A).
// Reintroduce them like this:
A(const A&) = default;
A& operator=(const A&) = default;
// Writing any copy ctor/assignment disables the compiler generated
// move ctor/assignment. If you still want them, reintroduce them.
A(A&&) = default;
A& operator=(A&&) = default;
};
A t_a = 1;
This doesn't use assignment. You need a constructor which takes an int argument.
int t_int = t_a;
You will need operator int() for this.
Note that it is a really bad idea to have a class which has both an implicit constructor from a type, and an implicit cast to the type. You will get all sorts of confusing errors when you try to do overload resolution.
Instead, I would make the constructor explicit, and write an explicit conversion function. That means you have to write:
int t_int = t_a.to_int();
But at least it's explicit.
Edit: Note that you can overload operator = for casting (either inside or outside the class), but neither of the code samples you gave will use it. = is used both for assignment and initialization, and both your samples are initialization (so won't use operator =)
I'm wondering if there is a way to implement copy constructors and assignment operators such that only a small modification is needed when these are redefined for a class.
For example, consider a class as such:
class Foo {
private:
int* mInt_ptr;
/* many other member variables
of different types that aren't
pointers */
public:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
~Foo();
};
Now, in order to deal with the pointer mInt_ptr I would need to handle it appropriately in the copy constructor and assignment operator. However, the rest of the member variables are safe to do a shallow copy of. Is there a way to do this automatically?
Once a class becomes large it may become tedious and unwieldy to explicitly write out the operations to copy the non-pointer member variables, so I'm wondering if there is a way to write, say, a copy constructor such as:
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
/* Do shallow copy here somehow? */
}
rather than the explicit form of:
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
mVar1 = tocopy.mVar1;
mVar2 = tocopy.mVar2;
...
...
mVarN = tocopy.mVarN;
}
Generally, don't use raw pointers, for exactly the reason that you're now fighting with. Instead, use a suitable smart pointer, and use copy-swap assignment:
class Foo
{
int a;
Zip z;
std::string name;
value_ptr<Bar> p;
public:
Foo(Foo const &) = default;
Foo & operator=(Foo rhs)
{
rhs.swap(*this);
return *this;
}
void swap(Foo & rhs)
{
using std::swap;
swap(a, rhs.a);
swap(z, rhs.z);
swap(name, rhs.name);
swap(p, rhs.p);
}
};
namespace std { template <> void swap<Foo>(Foo & a, Foo & b) { a.swap(b); } }
The value_ptr could be a full-blown implementation, or something simple such as this:
template <typename T> // suitable for small children,
class value_ptr // but not polymorphic base classes.
{
T * ptr;
public:
constexpr value_ptr() : ptr(nullptr) { }
value_ptr(T * p) noexcept : ptr(p) { }
value_ptr(value_ptr const & rhs) : ptr(::new T(*rhs.ptr)) { }
~value_ptr() { delete ptr; }
value_ptr & operator=(value_ptr rhs) { rhs.swap(*this); return *this; }
void swap(value_ptr & rhs) { std::swap(ptr, rhs.ptr); }
T & operator*() { return *ptr; }
T * operator->() { return ptr; }
};
How about you wrap all the shallow-copy bits in a small helper struct and use the default copy behaviour there.
class Foo {
private:
int* mInt_ptr;
struct helper_t
/* many other member variables
of different types that aren't
pointers */
} mHelper;
public:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
~Foo();
};
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
mHelper = tocopy.mHelper;
}
Using better primitives, as Kerrek suggested, seems like better design though. This is just another possibility.
Regardless if you use raw pointers or smart pointers the Kerrek's solution is right in the sense that you should make a copy constructor, destructor and swap and implement assignment using those:
class Foo
{
private:
int* mInt_ptr;
// many other member variables
// of different types
public:
Foo()
: mInt_ptr(NULL)
// initialize all other members
{}
Foo(const Foo& that)
: mInt_ptr(new int(*that.mInt_ptr) )
// copy-construct all other members
{}
Foo& operator=(const Foo& that)
{
// you may check if(this == &that) here
Foo(that).swap(*this);
return *this;
}
~Foo()
{
delete mInt_ptr;
// and release other resources
}
void swap(Foo& that)
{
std::swap(mInt_ptr, that.mInt_ptr);
// swap all members
}
};
The members are inline here just to keep it compact, usually it is not advisable to burden class definition with inline member definitions.
I want to have an object that contains a reference, and put that object into a vector...
Must I use smart pointers instead of a member references in any object I want to push into a vector? This was what I wanted to do:
#include <string>
#include <vector>
using namespace std;
class MyClass {
public:
MyClass(const string& str_ref); //constructor
MyClass(const MyClass& mc); //copy constructor
private:
string& my_str;
};
MyClass::MyClass(const string& str_ref) :
my_str(str_ref)
{}
MyClass::MyClass(const MyClass& mc) :
my_str(mc.my_str)
{}
int main() {
//create obj and pass in reference
string s = "hello";
MyClass my_cls(s);
//put into vector
vector<MyClass> vec;
vec.push_back(my_cls);
return 0;
}
//Throws Error
//ref.cpp:6:7: error: non-static reference member ‘std::string& MyClass::my_str’, can’t use default assignment operator
However it says I need to implement my own operator=() as the default generated one isn't valid but of course, there is no legal way to do so...
#include <string>
#include <vector>
using namespace std;
class MyClass {
public:
MyClass(const string& str_ref); //constructor
MyClass(const MyClass& mc); //copy constructor
MyClass operator=(const MyClass& mc); //operator =
private:
string& my_str;
};
MyClass::MyClass(const string& str_ref) :
my_str(str_ref)
{}
MyClass::MyClass(const MyClass& mc) :
my_str(mc.my_str)
{}
//not a constructor. should not construct new object
//and return that?
MyClass MyClass::operator=(const MyClass& mc) {
if (this != &mc) { //test for self-assignment.
my_str(mc.my_str); //can't reseat refs. this shouldn't work.
}
return *this;
}
int main() {
//create obj and pass in reference
string s = "hello";
MyClass my_cls(s);
//put into vector
vector<MyClass> vec;
vec.push_back(my_cls);
return 0;
}
//THROWS:
//ref2.cpp: In constructor ‘MyClass::MyClass(const string&)’:
//ref2.cpp:18:19: error: invalid initialization of reference of type ‘std::string& {aka //std::basic_string<char>&}’ from expression of type ‘const string {aka const //std::basic_string<char>}’
//ref2.cpp: In member function ‘MyClass MyClass::operator=(const MyClass&)’:
//ref2.cpp:29:18: error: no match for call to ‘(std::string {aka std::basic_string<char>}) //(std::string&)’
So am I forced to use a smart pointer here or anything other than a reference?
EDIT: This is a simplification. String& is not the object being passed, it's a more complex object itself containing a vector object.
You can store a raw pointer instead of a reference here. Raw pointers can be reseated, and so they're a good way to emulate reseatable references in C++.
class MyClass
{
public:
MyClass(const string& str_ref);
MyClass(const MyClass& mc);
// by the way, operator= should return a reference
MyClass& operator=(const MyClass& mc);
private:
string* my_str;
};
This way, operator= will be a cinch to implement.
How about using std::reference_wrapper<T>? Now you're not forced to refactor your code to allow a smart pointer, but you're also not using an internal pointer that someone may come along later and think they're supposed to delete.
class MyClass
{
public:
MyClass(string &str_ref)
: my_str(std::ref(str_ref))
{
}
private:
std::reference_wrapper<std::string> my_str;
};
One caveat. Please be sure to check for self-assignment:
MyClass& MyClass::operator=(MyClass const& from) {
if (this != &from) {
this->~MyClass();
new(this) MyClass(from);
}
return *this;
}
If you want to be able to still use the assignment operator of your member (i.e. std::string& operator=(std::string const&)) you cannot use the otherwise excellent suggestion of std::reference_wrapper. But you can rebuild your object from scratch using the copy constructor so your member may actually be a raw reference:
MyClass& MyClass::operator=(MyClass const& from) {
this->~MyClass();
new(this) MyClass(from);
return *this;
}