I have the following class:
class FixedByteStream {
public:
FixedByteStream() : size(0), address(NULL), existing(false) {}
FixedByteStream(int length) : existing(false) {
size = length;
address = new char[length];
}
FixedByteStream(int length, char* addr) : existing(true) {
size = length;
address = addr;
}
FixedByteStream(string* str, bool includeNull = false) : existing(true) {
size = (*str).length();
address = const_cast<char*>((*str).c_str());
if (includeNull){
++size;
}
}
~FixedByteStream() {
if (existing == false) {
delete [] address;
}
address = NULL;
}
int getLength() {
return size;
}
char* getAddressAt(int index) {
return &(address[index]);
}
char& operator[] (const int index) {
return address[index];
}
operator char*() {
return address;
}
private:
bool existing;
int size;
char* address;
};
And a very simple test that is able to produce the issue:
FixedByteStream received;
received = FixedByteStream(12);
received[0] = 't';
Valgrind warns about an invalid write, and debugging has shown why. FixedByteStream received; calls the constructor with no arguments (which is kind of stupid because it can't do anything). received = FixedByteStream(12); calls the constructor with the integer argument... and then immediately calls the destructor on itself, invalidating the object. It still works for some reason, but I'd rather it not be placed in such an odd predicament that throws warnings.
So, why is it being called there? I could somewhat understand if the destructor were called first, to get rid of the useless temporary object (not that it needs to), but I have used that kind of declare-now-assign-later pattern practically everywhere and never had such an issue before.
You are missing an assignment operator. Remember the rule of three (or five).
The problem is roughly like this:
T t; // default constructed t
t = T(2); // T(2) constructor with a single argument, assignment operator= called with this == &t
You provide no assignment operator so the pointer value in the temporary is simply copied into t and then the memory pointed to is deleted in the destructor of the temporary.
Also: Don't have a default constructor, if the object constructed is invalid.
If you object has any user defined constructor it is always constructed using a constructor. Just defining an object without any constructor arguments uses the default constructor independent of whether the object is being overwritten afterwards. That is
FixedByteStream received;
will call the default constructor. The next line is a bit more interesting:
received = FixedByteStream(12);
This line create a temporary FixedByteStream with the argument 12. Internally this will allocate some memory but since temporaries are destroyed at the end of the full expression (in this case essentially when the semicolon is reached) that won't you do much good. Once this temporary object is constructed it is assigned to received using the automatically generated copy assignment which would look something like this if you'd write it manually:
FixedByteStream& FixedByteStream::operator= (FixedByteStream& other) {
this->existing = other.existing;
this->size = other.size;
this->address = other.address;
return *this;
}
That is, once this assignment is executed, you have to identical copies of FixedByteStream, one of which is about to be destroyed and will release the resources just allocated. This is clearly not what you want, i.e. you definitely need to implement the copy assignment operator to make your class well-behaved. In general, the presence of a destructor which does anything interesting is a good hint at the fact that you'll need an assignment operator as well. In fact, there is another one of the generated operations, namely the copy constructor, which does roughly what the copy assignment does except that it copy constructs the members instead of assigning them. This is also not what you want with your class.
Now the interesting question becomes: how can FixedByteStream be fixed? Effectively, you'll need either to use reference counting to keep track of how many objects are currently looking at the FixedByteStream, allocate a copy of the content, or you need to use move semantic support (aka rvalue references) which is only available in C++2011. Unless you really know what you are doing I'd recommend copying the stream in all cases and leave a more advanced approach for later.
Step by step:
//create a new object using the default constructor
//I don't see why you think it's stupid that the constructor is called
//it's doing what you're telling it to do
FixedByteStream received;
//FixedByteStream(12) creates a temporary object
//you then copy this object in the received object you already have
//you're using the default operator =
//the temporary object is deleted after it is copied to received
received = FixedByteStream(12);
//received is a valid object
received[0] = 't';
EDIT:
As I see there's a lot of wrong answers for this question, I'll explain further. I might get some hate for this, but this is a pretty important concept and I downvoted so that a wrong answer doesn't get accepted and taken from granted.
You're basically initializing some object on the stack.
I'll simplify your case:
class A
{
A() {}
A(const A& other) {}
A& operator = (const A& other) {}
};
Let's talk about scope:
{ //begin scope
A a; //object a is created here
//default constructor is called
} //a is destroyed here
//destructor is called
So far so good.
Now, assignment:
{
//two objects are created with default constructor
A a;
A b;
//object b is assigned to a
//operator = will be called
//both objects are still alive here
a = b;
//...
} // a and b will be destroyed, destructor called
On to the last part:
{
A a;
a = A();
}
is pretty much equivalent to:
{
A a;
{
A b;
a = b;
}
}
When you call a = A(), A() creates a temporary object which is assigned to a and then destroyed.
So object b in my simplification is the temporary object that gets destroyed. Not a, your original, therefore a is still valid.
Not the assignment operator declaration. If you don't define one, a default is used. You probably want to write your own in this case.
FixedByteStream(12) is assigned to received through the default operator=. Notice that you didn't allocate FixedByteStream(12) in the heap by using new, but rather allocated it in local scope without specifying a name for the variable that would hold it.
Your code is somewhat similar to:
FixedByteStream received;
FixedByteStream temp(12);
received = temp;
received[0] = 't';
Only in my example temp has a name and its scope is the entire function, and in your test code temp doesn't have a name, it exists for one line only and then gets destroyed.
The FixedByteStream(12) object you've created cannot be used after this line because it's not even a named varaible.
Object is already initialized on this line
FixedByteStream received;
On line
received = FixedByteStream(12);
You reinitialize it. The correct way to do this is:
FixedByteStream received(12);
// Or
FixedByteStream *received;
received = new FixedByteStream(12);
(I'd definitely go for first one)
It seems you don't understand object lifecycle and mistakenly interpret this code as a Java code.
When you write FixedByteStream received; an object of type FixedByteStream is created using the no-argument constructor. And when you write received = FixedByteStream(12); another object is created, = operator is called and the newly created object is desctructed.
Also you didn't override operator= so the object is copied by bytes, which is not correct.
Related
I have a class in my C++ code which has its own move constructor. A simplified version is shown here:
class myClass {
//In this example, myClass must manually manage allocating
//and freeing a memory buffer.
char *mem;
//...
//Regular constructor, copy constructor, etc
//...
myClass(myClass &&other) {
//Swap our memory pointer with other's memory pointer
char *tmp = other.mem;
other.mem = mem;
mem = tmp;
}
//...
//Destructor, other member functions, etc.
//...
}
In normal situations, this works fine. However, recently I needed to make a vector of these objects:
vector<myClass> v;
v.reserve(10); //Make space, but do not construct
v.push_back(myClass()); //Problem!
After getting a segfault and stepping through with gdb, I eventually discovered what should have been obvious: if you try to construct an object from an rvalue reference, this can result in using the move constructor on uninitialized memory.
How are you supposed to write a move constructor when it's possible that you're swapping garbage into the other class? Is there some way to detect this?
How are you supposed to write a move constructor when it's possible that you're swapping garbage into the other class? Is there some way to detect this?
An object that is not initialized holds an indeterminate value until assigned another value [basic.indet]/1. You're basically not allowed to do anything with an object holding an indeterminate value except for assigning it a proper value [basic.indet]/2. Since you're not even allowed to look at the value an object holds unless it has been initialized or assigned a value, there cannot possibly be a way to detect whether an object has been initialized just by looking at the object itself (because you're not allowed to even take a look). Thus, strictly speaking, you're actually not just "swapping garbage values into the other class", you're invoking undefined behavior. Garbage being swapped is just how that undefined behavior will typically manifest.
The solution to the problem is simple: Make sure that your pointer is always initialized to a valid value, e.g., nullptr:
class myClass {
//In this example, myClass must manually manage allocating
//and freeing a memory buffer.
char *mem = nullptr;
//...
//Regular constructor, copy constructor, etc
//...
myClass(myClass &&other) {
//Swap our memory pointer with other's memory pointer
char *tmp = other.mem;
other.mem = mem;
mem = tmp;
}
//...
//Destructor, other member functions, etc.
//...
}
Rather than implement the move constructor yourself, consider, e.g., just using a member of type std::unique_ptr and simply relying on the implicitly defined move constructor. For example:
class myClass
{
std::unique_ptr<char[]> mem;
// regular constructor, copy constructor, etc.
myClass(myClass&&) = default;
// other member functions, etc.
};
Don't swap the pointers in the constructor. That's not how you write move constructors. Swapping is for move-assignment, when both objects are live.
Constructors exist to initialize an object. As such, the memory they start with is always in the "uninitialized" state. So unless you initialize a member (or it has a default constructor that initializes it for you), the member's value will start uninitialized.
The correct way to handle this is just copy the pointer in the member initializer, then null out the other one.
myClass(myClass &&other) : mem(other.mem) {
other.mem = nullptr;
}
Or, with C++14 (and C++20 with a constexpr version), you can exchange the value:
myClass(myClass &&other)
: mem(std::exchange(other.mem, nullptr))
{}
I'm trying to call a constructor of 1 object with the constructors for other objects, and am having a problem with things deleting. The important bits of code look like the following:
class command {
public:
command(const string& s) {
x = (char*) calloc(s.size()+1, 1);
memcpy(x, s.c_str());
}
~command() {
free(x);
}
private:
char* x;
}
this constructor mallocs a char* which needs to be freed in the destructor.
class pair {
public:
pair(command comm1in, command comm2in)
:comm1(comm1in), comm2(comm2in){};
private:
command comm1;
command comm2;
}
this one tries to set its 2 fields to the commands sent in.
I think it also calls their copy constructors (might be wrong though)
in another function, I call the constructor for pair like so
pair p(command("something"), command("something else"));
unfortunately, this has the effect of calling the destructors on the just created values and then the copy constructor in the constructor for pair.
Is there a good way to initalize comm1 and comm2 without going through the copy/delete process?
I think c++11 has rValue references and std::move but I don't know if those come into play here.
So I asked one of my professors about this and then played around. This was extremely helpful.
Here is what the above code should look like if we want to avoid double-freeing the pointer x.
command:
class command {
public:
command(const string& s) {
x = (char*) calloc(s.size()+1, 1);
strcpy(x, s.c_str());
}
command(command&& in): x(in.x) {
other.x = nullptr;
}
~command() {
if(x) delete x;
}
private:
char* x;
}
pair:
class pair {
public:
pair(command&& comm1in, command&& comm2in)
:comm1(std::move(comm1in)), comm2(std::move(comm2in)){};
private:
command comm1;
command comm2;
}
calling pair's constructor looks the same
pair(command("something"), command("something else"));
Learnings:
calling the delete constructor is unavoidable, so instead we must define a move constructor for command that gives it the R-value's pointer and sets the R-value's pointer to null. (so when its destructor is called it doesn't deallocate still-pointed-to memory)
To allow objects to be moved into another object, initialize them with std::move()
Why do this?
This allows for us to ensure that only that 1 instance of command will have the object.
We don't have to malloc / call new and get space on the heap.
the command is automatically deleted when pair is deleted, so we don't have to write a delete function
I'm currently trying to work out a .cpp file for a project, but I'm getting a seg fault whenever I try to run it with the test file provided to met. I suspect I've found where the error occurs, but I can't for the life of me find a solution.
Basically, the class Product is initialized in the test file as seen below
Product * orderItem = new Product(*wonkaBar_retail);
Where wonkaBar_retail is a pointer to a Product object - so basically, the constructor for Product takes in an object of its own type... I'm not even sure that's supposed to work. As I said, this code, including the part that instantiates wonkaBar_retail was provided, so I tried compensating by making a Constructor like this
Product(Product) {
//Constructor in the header file
}
and even like this
Product(const Product&) {
//Other style
}
That just gave me a handful of compiler errors the compiler didn't even bother to explain...
Can someone clarify how this is supposed to work, and if this would even cause a segfault in the first place?
The line you provided uses a copy constructor for the class Product which is perfectly legal. In fact, if you don't provide your own copy constructor for a class a compiler will generate one for you.
A copy constructor takes a reference to another object of the same type and initializes a new object to the same state as the other object. The copy constructor signature usually looks like this:
Product(const Product& other);
For simple classes the compiler generated copy constructor will work just fine, however for non-trivial classes, e.g. containing pointers to dynamically allocated objects you should implement your own.
Consider the following class:
class Buffer
{
public:
Buffer(int dataSize) : m_dataSize(dataSize) { m_data = new char[m_dataSize]; }
~Buffer() { delete[] m_data; }
private:
int m_dataSize;
char* m_data;
};
The default copy constructor for this class will look like this:
Buffer::Buffer(const Buffer& other)
{
m_dataSize = other.m_dataSize;
m_data = other.m_data;
}
This is clearly not what you want. For one, if an object you copy gets deleted, the data your new object is pointing to will also get deleted. And then when you delete your new object you'll attempt to delete the same data twice, which is very bad.
What you really want to do then is to allocate new m_data for your new object and copy the data from the other object like this:
Buffer::Buffer(const Buffer& other)
{
m_dataSize = other.m_dataSize;
m_data = new char[m_dataSize];
for (int i = 0; i < m_dataSize; ++i)
{
m_data[i] = other.m_data[i];
}
}
My programming background is the Java world, but I've just started learning C++. I've stumbled across this rather trivial and probably pretty noobish problem that somehow puzzles me as a Java programmer:
I have a class with an array which is initialized via new in the constructor and deleted in the destructor. Now when I create an object of this class and assign another object of this class to the same variable (at least that is what I think it is), the delete[] method in the destructor seems to be called twice when the variables leave the scope (in this case the main() function) (the debugger gives me an _BLOCK_TYPE_IS_VALID assertion failed warning).
Why is that? Why isn't the deconstructor called before I assign a new object to f? How could I explicitely delete Foo(1)? What exactly happens here?
class Foo{
private:
int *field;
public:
Foo(int size){
field = new int[size];
}
~Foo(){
delete[] field;
}
};
int main(){
Foo f = Foo(1);
f = Foo(2);
}
There is something in the C++ world called the Rule Of Three.
A class will automatically generate a destructor, copy constructor, and assignment operator for you.
If you have to manually define one of those functions, you probably have to define all three of them.
In your case, you should define the two copy functions, so that a copy of Foo gets its own copy of field. Add these two functions:
class Foo{
Foo( const Foo &f ) {
size = f.size;
field = new int[size];
std::copy( f.field, f.field + size, field );
}
Foo& operator=( const Foo &f ) {
// Leverage the logic that was already written in the copy constructor
Foo tmp(f);
std::swap( *this, temp );
return *this;
}
};
Note that I'm assuming that you've stored size in the Foo object. You would probably need to store that information anyway in a real-life application
You're not following the rule of three, which is bad. Because the default copy constructor does a shallow copy, all your automatic variables (f and the temporaries) have the field member pointing to the same int, which is destroyed multiple times when the destructor is called.
Implement a proper copy constructor, or use C++ idioms and avoid manual management alltogether - i.e. use a std::vector instead.
myClassVar = MyClass(3);
I expected destructor being called on the previously created myClassVar on the left.
But it is actually being called on the new object that's created by MyClass(3).
My full test code and output follows..
edit
How do I fix the problem?
Implement an assignment operator?
MyClass actually has pointers, and MYSQL_STMT*, I wonder how should I deal with MYSQL_STMT* variable.
I just need MyClassVar(3) object not the MyClassVar() which was first created when ClientClass object was created.
I came across this situation fairly often, and wonder if there's a good way to do it.
#include <stdio.h>
class MyClass
{
public:
MyClass() { printf("MyClass %p\n", this); }
MyClass(int a) { printf("Myclass(int) %p\n", this); }
~MyClass() { printf("~MyClass %p\n", this); }
private:
int mA;
};
class ClientClass
{
public:
void Foo()
{
printf("before &myClassVar : %p\n", &myClassVar);
myClassVar = MyClass(3); // this is the important line
printf("after &myClassVar : %p\n", &myClassVar);
}
private:
MyClass myClassVar;
};
int main()
{
ClientClass c;
c.Foo();
return 0;
}
MyClass 0x7fff5fbfeba0
before &myClassVar : 0x7fff5fbfeba0
Myclass(int) 0x7fff5fbfeb70
~MyClass 0x7fff5fbfeb70 // <--- here destructor is called on the newly created object
after &myClassVar : 0x7fff5fbfeba0
~MyClass 0x7fff5fbfeba0
Here's how the critical line breaks down:
myClassVar = MyClass(3);
First, MyClass(3) calls constructor and returns the object.
Second, myClassVar = copies the object to myClassVar.
Then the statement ends. The object (which is an immediate) is dead, and thus the destructor is invoked.
EDIT :
As for how to get around this. The only way I can think of is to use a placement new. I'm not sure if there's a better solution other than making a "set" method.
myClassVar = MyClass(3);
myClassVar continues to exist after this line. The lifetime of MyClass(3) ends at the semicolon.
As the other posts mentioned the object with the custom constructor MyClass(3) gets destroyed after the assignment operation myClassVar = MyClass(3). In this case you do not need a custom assignment operator because the compiler generated one copies the member mA to the already existing object myClassVar.
However since MyClass defines its own destructor you should adhere to the rule of three, which mandates that in such a case you should implement a custom assignment operator as well.
Responding to your edit: how do you fix what problem? It's not clear
what the problem is. If your class needs a destructor (and there's no
polymorphism in play), it probably needs both an assignment operator and
a copy constructor. Similarly, when "tracking" construcctions and
destructions, you should probably provide both as well, since they will
be called.
Otherwise: if the problem is that you're constructing and then
assigning, rather than constructing with the correct value immediately,
the simple answer is "don't do it". The compiler does what you tell it
to. If you write:
MyClass var;
var = MyClass(3);
you have default construction, followed by the construction of a
temporary, assignment, and the destruction of the temporary. If you
write:
MyClass var(3);
or
MyClass var = 3;
you only have one construction. (Note that despite appearances, there
is no assignment in the last snippet. Only construction.)
For class members, this difference appears in the way you write the
constructor:
ClientClass::ClientClass() { var = MyClass(3); }
is default construction, followed by creation, assignment and
destruction of a temporary;
ClientClass::ClientClass() : var( 3 ) {}
is just construction with the correct value. (Rather obviously, this
second form is preferred.)