Say I have the following structures
struct X
{
X () = delete;
X(const std::string &);
//all other copy/move/assignment ctors PLUS dtor are defined, just the default is deleted
/* members */
};
struct Y
{
X & x_object;
Y( const std::string & str): Y { *(new X { str }) } { }
Y( X &obj): x_object(obj) { }
~Y() {
// x_object is needed to be freed here, would
}
};
How do I know if x_object is allocated on the heap or the stack? If I declared x_object as a std::shared_ptr<X> then it would mean I'd need to make a copy of obj in the Y ctor that takes an X object. Calling delete on objects allocated on the stack AFAIK is an undefined behaviours(§ 5.3.5. I'd have done a delete &x_object ). OR is there any other way I can perform this operation which MUST directly reflect in whatever X object that was passed(pretending for a moment that X objects are noncopyable )?
A way to solve your deallocation issue:
struct Y
{
public:
Y(const std::string & str) :
x_owned(new X { str }), // Have ownership of X
x_object(*x_owned)
{}
Y(X &obj) : x_owned(), x_object(obj) {}
~Y() = default;
private:
std::unique_ptr<X> x_owned;
X& x_object;
};
You can't decide whether an object has automatic lifetime ("stack") or dynamic lifetime ("heap"), at least not in a portable way. It's also very non-idiomatic to do this even if you could.
In C++ you must decide and know who is responsible for allocating and deallocating an object. If you really need the flexibility, you could add parameter (or a different overload) to allow the user to indicate whether they want the object destroyed in the destructor or not.
Related
I have two classes one of them has an object of another class as a data member and it's constructor accepts the class object to initialize the data member object.
class x{
public:
x(int a, int b)
{ cout << a << b;}
};
class y{
x temp;
y(x& o){ this-> temp = o;}
};
But compiler shows an error in y::y(x&): no matching function to call x::x()
I am using codeblocks 16.01
You have defined the constructor:
x(int a, int b)
in x. This means that the compiler will no longer define any constructors for you, this includes the x() constructor. So you can only construct x with x(int, int). Here in your code:
x temp;
y(x& o) { // < No initializer list
You attempt to default construct x, but x has no default constructor! Either define one, or construct x in the initializer list with the constructor you have provided.
For example:
y(x& o) : x(0, 0) {
But you will create your object then you will use the implicitly defined copy-assignment operator to assign it, which is a bit of a waste of time. You can actually solve all these problems by using the copy-constructor:
class x{
...
x(const x ©) { // Define a copy constructor or just use
// the implicitly defined one.
Then in y, just use it in y's initializater list:
x temp;
y(x& o) : temp(o) {}
y(x& o){ this-> temp = o; }
is not very C++ idiomatic.
I. As a rule, you should avoid requiring more access rights than needed. Here, you're likely to not mutate the construction argument, so you don't need to pass it by a mutable reference:
y(x const &o);
II. Member initialization is done very differently in C++:
y(x const &o): temp(o) {}
When you write
y(x const &o) { temp = o; } // please avoid writing `this->'
then what happens is: first, temp is constructed and default-initialized (prior to the opening brace); then, inside the braces, temp is already a valid object, so what follows is a copy-assignment. In your case, x is not default-constructible, so compilation fails.
I have a struct like this:
struct OBJ {
int x;
const int y;
OBJ& operator=(OBJ &&oth)
{
y = oth.y; // this is disallowed
return *this;
}
}
And an example code
void func() {
static OBJ obj;
OBJ other; // random values
if(conditon)
obj = std::move(other); //move
}
I understand this as obj is Non const OBJ with const member y. I can't change just y but I should be able to change whole object (call destructor and constructor). Is this possible or the only proper solution is to remove my const before y, and remember to don't change by accident?
I need to store my static obj between func call but if condition is true i want to move other object in place of this static object.
I would suggest moving to std::unique_ptr:
void func() {
static std::unique_ptr<OBJ> obj = std::make_unique<OBJ>();
std::unique_ptr<OBJ> other = std::make_unique<OBJ>(); // random values
if(condition)
obj = std::move(other); //move
}
This should be your choice in many cases where there is a need to move something that cannot be moved, to hold an unknown polymorphic type or any other case where you cannot deal with the actual type.
You're doing constructors wrong. Constructors should initialize, not assign:
OBJ(OBJ &&oth) : y(oth.y) {}
// ^^^^^^^^^^
Also, constructors cannot return *this, since they have no return type.
An assignment operator for your class doesn't make sense since the class has unassignable members (namely constants). (You could of course write a custom assignment that doesn't modify the const member, but then you'd have a truly weird class that has extremely surprising behaviour.)
What about writing the move-assignment operator this way:
OBJ& operator=(OBJ&& other) {
this->~OBJ();
new(this) OBJ(other.x, other.y);
return *this;
}
You would also need a constructor:
OBJ(const int x, const int y)
: x(x), y(y)
{
}
Disclaimer
I'm trying to allocate an array of objects that are neither copy constructible, assignable nor has a default constructor. The objects have arguments that are determined at run time. I know that you can solve this problem by having an array of pointers or cleverly using placement new but I'm more interested in if this is possible to do cleanly with C++11 (1y) magic. So please, this is purely of theoretical interest so avoid trying to solve "my problem" by offering a work around.
The code...
...So the question is: Is there a way to make the following work in C++11 or C++14:
class X{
public:
explicit X(int a){...}
X(const X&) = delete;
void operator = (const X&) = delete;
private:
...
};
class Y{
public:
Y(const std::vector<int>& args) {
x = new X[]{args};
}
~Y(){
delete [] x;
}
private:
X* x;
};
Criteria
Specifically I'm looking for a solution/construct that meets the following criteria:
X is not copy constructible.
X is not assignable.
X does not have a default no-argument constructor (construction has intended side-effects).
The arguments to X's constructor are not known until run time.
All instances of X must be laid out contiguously in memory.
X must be properly destructed when the array is deleted from it's base pointer (or if an intermediate class is used, when the intermediate object is destructed). This rules out array of pointers and naivë use of placement new.
Edit / Addendum
I forgot to mention that move constructor is not available. In the actual case at hand, X spawns a worker thread and is executing in the context of this of the initially constructed object, any attempt to use a move constructor will corrupt the state of the executing thread.
You can use std::vector and its emplace_back function if you make X at least movable.
class X{
public:
explicit X(int){}
X(X&&) = default;
X(const X&) = delete;
void operator = (const X&) = delete;
};
int main() {
std::vector<X> xs;
xs.emplace_back(0);
xs.emplace_back(1);
xs.emplace_back(2);
xs.emplace_back(3);
}
(If you declare a copy constructor, even if that declaration deletes it, the compiler will not automatically generate any special move member, so you need to explicitly request them)
This basically boils down to the "array with placement new" strategy, but all abstracted away into high-level notions.
If you cannot make use of a movable type, you have to implement a vector-like class that pre-allocates storage and never reallocates. There is nothing similar in the standard library.
You're going to have to keep track of the constructed elements by hand, but you can use allocator to help:
class Y{
public:
Y(const std::vector<int>& args):
alloc{},
n{args.size()},
x{alloc.allocate(n)}
{
auto end = x;
try {
for (auto arg: args)
alloc.construct(end++, arg);
} catch (...) {
while (end != x)
alloc.destroy(--end);
alloc.deallocate(x, n);
throw;
}
}
~Y() {
for (auto end = std::next(x, n); end != x; --end)
alloc.destroy(end);
alloc.deallocate(x, n);
}
private:
std::allocator<X> alloc;
const std::size_t n;
const X *x;
};
A class that is neither copyable nor movable, nor has a default constructor, cannot be held in a standard container (doesn't meet the requirements) or a variable-sized array allocation (which only allows argument specification for a fixed number of elements).
This means you need to allocate raw memory instead and use placement new to construct the objects. You can wrap this in a fixed-space vector class.
template <typename T>
class fixed_capacity_vector {
public:
using size_type = std::size_t;
fixed_capacity_vector(size_type capacity)
: data_(::operator new(capacity * sizeof(T)), size_(), capacity_(capacity)
{}
fixed_capacity_vector(const fixed_capacity_vector&) = delete;
fixed_capacity_vector(fixed_capacity_vector&&) = delete;
fixed_capacity_vector& operator =(const fixed_capacity_vector&) = delete;
fixed_capacity_vector& operator =(fixed_capacity_vector&&) = delete;
~fixed_capacity_vector() {
for (size_type i = 0; i < size_; ++i) data_[i].~T();
::operator delete(data_);
}
template <typename... Args>
T& emplace_back(Args&&... args) {
if (size_ == capacity_) throw out_of_range();
new (data_ + size_) T(std::forward<Args>(args)...);
++size_;
return data_[size_-1];
}
private:
T* data_;
size_type size_;
size_type capacity_;
};
When pointers point to something declared in the same class, am I right in thinking that if you copy such an object that there are multiple sets of pointers but they all point to the same object(s)?
Does this mean there are other objects in the other class instances that have been created but that nothing is pointing to?
And as a side question, would I be right in thinking that a shared pointer would point all the classes at ONE set of objects but in a safe way?
yes - when you don't define a copy constructor the compiler will issue one for you - which will do a shallow copy - just copy the values(i.e the address) of the pointers.
So the two objects(original and 'copy') will have pointer fields pointing at the same object.
If you don't deep copy the object i.e. if you don't override the copy c'tor and do a shallow copy, the pointer(s) will point to the same instance of an object. If you then delete one of the shallow - copied objects then the pointers of the other objects will point to garbage. If you dereference them in any way your program will crash.
Same thing can happen with the assignment operator. So when you have pointers overload them both.
An example:
struct Message
{
Message(const LogType_E & type_in = LOG_ERROR, const unsigned int & domain_in = 0, const int & msgId_in = 0, const char * msg_in = "");
int myMsgID; //!< message id
unsigned int myDomain; //!< message domain
LogType_E myType; //!< message type
char * myMsg; //!< actual message
~Message()
{
if(myMsg != NULL) delete [] myMsg;
}
Message(const Message &);
const Message& operator=(const Message & rhs);
};
This is a "message" type used to hold a message with other thingies.
Implementation would look like :
Message::Message(const Message & cp_in):myType(cp_in.myType), myDomain(cp_in.myDomain), myMsgID(cp_in.myMsgID), myMsg(NULL)
{
if(cp_in.myMsg != NULL)
{
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
}
const Message & Message::operator =(const AX::Base::Log::Message &cp_in)
{
if (this == &cp_in) // protect against invalid self-assignment
return *this;
//deallocate old memory
if(myMsg != NULL) delete [] myMsg;
if(cp_in.myMsg != NULL)
{
//allocate new memory and copy the elements
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
// copy other data members
myType = cp_in.myType;
myDomain = cp_in.myDomain;
myMsgID = cp_in.myMsgID;
return *this;
}
That said, please use std::string to avoid all these things - that was just a proof of concept example.
Imagine you have a class like so that exhibits the problem you have asked in the question
class Foo{};
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
};
And code like so
Bar x ;
Bar y = x;
The above code will cause an core dump because both y and x will point to the same Foo and the destructor will try to delete the same Foo twice.
ALTERNATIVE 1
Declare but not provide a definition so that Bar is never copy constructor or assigned. The will ensure that Bar y = x will have a link error as you have designed the class not be copied.
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar &);
Bar& operator= (const Bar &);
};
ALTERNATIVE 2
Provide a copy constructor and assignment operator that do the right thing. Instead of the compiler provided default implementation of copy and assignment that do shallow copy you are duplicating Foo so that both x and y have their own Foo
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
}
Bar& operator= (const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
return *this;
}
};
ALTERNATIVE 3 (BEST)
Use C++11 shared_ptr or boost and omit the copy and assigment as the default compiler provided one will do the right thing as shared_ptr is ref counted and will delete Foo only once even though both x and y share the same Foo. Also notice that ~Bar needs to no explicit clean up as mFoo will automatically be deleted in std::shared_ptr<Foo> destructor when the the refcount of Foo becomes zero.
class Bar
{
public:
std::shared_ptr<Foo> mFoo;
Bar() :mFoo( new Foo() ) {}
~Bar() { }
};
Let the code do the talking to clear things up:
struct X
{
int data;
int *ptr;
X() : ptr(&data) {}
};
X a;
X b = a; // yes, `a.ptr` points to `b.data`!
Indeed, the pointers will be copied verbatim and will keep pointing into the source of the copy.
Use pointer-to-members
Fixable thus:
struct X
{
int data;
int X::*ptr;
X() : ptr(&X::data) {}
};
X a;
X b = a; // now, `a.ptr` points to `a.data`
Extending this sample with some more usage hints https://ideone.com/F0rC3
a.ptr = &X::data2; // now `a.ptr` points to `a.data2`
// `b.ptr` points to `b.data1`
b = a; // `b.ptr` points to `b.data2` too
// Usage hint:
int deref = a.*(a.ptr); // gets the field pointed to by a.ptr, from the instance a
deref = b.*(b.ptr); // gets the field pointed to by b.ptr, from the instance b
// but of course you could get fancy and do
deref = a.*(b.ptr); // gets the field pointed to by b.ptr, **but** from the instance a
That would do what you probably want. Although, why you want that is beyond me (and beyond C++, possibly)
Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);