I have class like this
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
virtual ~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
}
And then I push instances into a std::vector like this:
stack.push_back(variable(0));
I expect that the destructor of variable will be called but the if won't enter until a value is assigned to type because I expect the constructor I provide will be called when the instance is copied into the vector. But for some reason it is not.
After calling stack.push_back the destructor (of the copy?) is ran and type has some random value like if the constructor was never called.
I can't seem to figure what I am doing wrong. Please help! ^_^
EDIT:
Ok here is a self contained example to show what I mean:
#include <iostream>
#include <vector>
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
};
static void pop_int(variable& var)
{
delete (int*)var.value;
}
static void push_int(variable& var)
{
var.type = 1;
var.value = new int;
var.on_pop = &pop_int;
}
typedef void(*func1)(variable&);
func1 push = &push_int;
int main()
{
std::vector<variable> stack;
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
return 0;
}
The program above outputs the following:
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Process returned 0 (0x0) execution time : 0.602 s
Press any key to continue.
Welcome to RVO and NRVO. This basically means that the compiler can skip creating an object if it's redundant- even if it's constructor and destructor have side effects. You cannot depend on an object which is immediately copied or moved to actually exist.
Edit: The actual value in the vector cannot be ellided at all. Only the intermediate variable variable(0) can be ellided. The object in the vector must still be constructed and destructed as usual. These rules only apply to temporaries.
Edit: Why are you writing your own resource management class? You could simply use unique_ptr with a custom deleter. And your own RTTI?
Every object that was destructed must have been constructed. There is no rule in the Standard that violates this. RVO and NRVO only become problematic when you start, e.g., modifying globals in your constructors/destructors. Else, they have no impact on the correctness of the program. That's why they're Standard. You must be doing something else wrong.
Ultimately, I'm just not sure exactly WTF is happening to you and why it's not working or what "working" should be. Post an SSCCE.
Edit: In light of your SSCCE, then absolutely nothing is going wrong whatsoever. This is entirely expected behaviour. You have not respected the Rule of Three- that is, you destroy the resource in your destructor but make no efforts to ensure that you actually own the resource in question. Your compiler-generated copy constructor is blowing up your logic. You must read about the Rule of Three, copy and swap and similar idioms for resource handling in C++, and preferably, use a smart pointer which is already provided as Standard like unique_ptr which does not have these problems.
After all, you create six instances of variable- three temporaries on the stack, and three inside the vector. All of these have their destructors called. The problem is that you never considered the copy operation or what copying would do or what would happen to these temporaries (hint: they get destructed).
Consider the equal example of
int main()
{
variable v(0);
push_int(v);
variable v2 = v;
return 0;
}
Variable v is constructed and allocates a new int and everything is dandy. But wait- then we copy it into v2. The compiler-generated constructor copies all the bits over. Then both v2 and v are destroyed- but they both point to the same resource because they both hold the same pointer. Double delete abounds.
You must define copy (shared ownership - std::shared_ptr) or move (unique ownership - std::unique_ptr) semantics.
Edit: Just a quick note. I observe that you actually don't push into items until after they're already in the vector. However, the same effect is observed when the vector must resize when you add additional elements and the fundamental cause is the same.
The destructor is called 6 times. A constructor is called six times. Just not the one you intended.
Ok. I've been reading some more about the intrinsics of different containers and, apparently, the one that does the job I'm trying to accomplish here is std::deque.
Related
After using std::move in a variable that might be a field in a class like:
class A {
public:
vector<string>&& stealVector() {
return std::move(myVector);
}
void recreateMyVector() {
}
private:
vector<string> myVector;
};
How would I recreate the vector, like a clear one? What is left in myVector after the std::move?
The common mantra is that a variable that has been "moved-from" is in a valid, but unspecified state. That means that it is possible to destroy and to assign to the variable, but nothing else.
(Stepanov calls this "partially formed", I believe, which is a nice term.)
To be clear, this isn't a strict rule; rather, it is a guideline on how to think about moving: After you move from something, you shouldn't want to use the original object any more. Any attempt to do something non-trivial with the original object (other than assigning to it or destroying it) should be carefully thought about and justified.
However, in each particular case, there may be additional operations that make sense on a moved-from object, and it's possible that you may want to take advantage of those. For example:
The standard library containers describe preconditions for their operations; operations with no preconditions are fine. The only useful ones that come to mind are clear(), and perhaps swap() (but prefer assignment rather than swapping). There are other operations without preconditions, such as size(), but following the above reasoning, you shouldn't have any business inquiring after the size of an object which you just said you didn't want any more.
The unique_ptr<T, D> guarantees that after being moved-from, it is null, which you can exploit in a situation where ownership is taken conditionally:
std::unique_ptr<T> resource(new T);
std::vector<std::function<int(std::unique_ptr<T> &)> handlers = /* ... */;
for (auto const & f : handlers)
{
int result = f(resource);
if (!resource) { return result; }
}
A handler looks like this:
int foo_handler(std::unique_ptr<T> & p)
{
if (some_condition))
{
another_container.remember(std::move(p));
return another_container.state();
}
return 0;
}
It would have been possible generically to have the handler return some other kind of state that indicates whether it took ownership from the unique pointer, but since the standard actually guarantees that moving-from a unique pointer leaves it as null, we can exploit that to transmit that information in the unique pointer itself.
Move the member vector to a local vector, clear the member, return the local by value.
std::vector<string> stealVector() {
auto ret = std::move(myVector);
myVector.clear();
return ret;
}
What is left in myVector after the std::move?
std::move doesn't move, it is just a cast. It can happen that myVector is intact after the call to stealVector(); see the output of the first a.show() in the example code below. (Yes, it is a silly but valid code.)
If the guts of myVector are really stolen (see b = a.stealVector(); in the example code), it will be in a valid but unspecified state. Nevertheless, it must be assignable and destructible; in case of std::vector, you can safely call clear() and swap() as well. You really should not make any other assumptions concerning the state of the vector.
How would I recreate the vector, like a clear one?
One option is to simply call clear() on it. Then you know its state for sure.
The example code:
#include <initializer_list>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class A {
public:
A(initializer_list<string> il) : myVector(il) { }
void show() {
if (myVector.empty())
cout << "(empty)";
for (const string& s : myVector)
cout << s << " ";
cout << endl;
}
vector<string>&& stealVector() {
return std::move(myVector);
}
private:
vector<string> myVector;
};
int main() {
A a({"a", "b", "c"});
a.stealVector();
a.show();
vector<string> b{"1", "2", "3"};
b = a.stealVector();
a.show();
}
This prints the followings on my machine:
a b c
(empty)
Since I feel Stepanov has been misrepresented in the answers so far, let me add a quick overview of my own:
For std types (and only those), the standard specifies that a moved-from object is left in the famous "valid, but unspecified" state. In particular, none of the std types use Stepanov's Partially-Formed State, which some, me included, think of as a mistake.
For your own types, you should strive for both the default constructor as well as the source object of a move to establish the Partially-Formed State, which Stepanov defined in Elements of Programming (2009) as a state in which the only valid operations are destruction and assignment of a new value. In particular, the Partially-Formed State need not represent a valid value of the object, nor does it need to adhere to normal class invariants.
Contrary to popular belief, this is nothing new. The Partially-Formed State exists since the dawn of C/C++:
int i; // i is Partially-Formed: only going out of scope and
// assignment are allowed, and compilers understand this!
What this practically means for the user is to never assume you can do more with a moved-from object than destroy it or assign a new value to it, unless, of course, the documentation states that you can do more, which is typically possible for containers, which can often naturally, and efficiently, establish the empty state.
For class authors, it means that you have two choices:
First, you avoid the Partially-Formed State as the STL does. But for a class with Remote State, e.g. a pimpl'ed class, this means that to represent a valid value, either you accept nullptr as a valid value for pImpl, prompting you to define, at the public API level, what a nullptr pImpl means, incl. checking for nullptr in all member functions.
Or you need to allocate a new pImpl for the moved-from (and default-constructed) object, which, of course, is nothing any performance-conscious C++ programmer would do. A performance-conscious C++ programmer, however, would also not like to litter his code with nullptr checks just to support the minor use-case of a non-trivial use of a moved-from object.
Which brings us to the second alternative: Embrace the Partially-Formed State. That means, you accept nullptr pImpl, but only for default-constructed and moved-from objects. A nullptr pImpl represents the Partially-Formed State, in which only destruction and assignment of another value are allowed. This means that only the dtor and the assignment operators need to be able to deal with a nullptr pImpl, while all other members can assume a valid pImpl. This has another benefit: both your default ctor as well as the move operators can be noexcept, which is important for use in std::vector (so moves and not copies are used upon reallocation).
Example Pen class:
class Pen {
struct Private;
Private *pImpl = nullptr;
public:
Pen() noexcept = default;
Pen(Pen &&other) noexcept : pImpl{std::exchange(other.pImpl, {})} {}
Pen(const Pen &other) : pImpl{new Private{*other.pImpl}} {} // assumes valid `other`
Pen &operator=(Pen &&other) noexcept {
Pen(std::move(other)).swap(*this);
return *this;
}
Pen &operator=(const Pen &other) {
Pen(other).swap(*this);
return *this;
}
void swap(Pen &other) noexcept {
using std::swap;
swap(pImpl, other.pImpl);
}
int width() const { return pImpl->width; }
// ...
};
Yes I've searched but I can't find the answer. I have a vector that is a member of a class. This vector is given some values (in this case just 1) in the class constructor. As soon as the constructor is finished, the destructor for the objects in the vector is called.
Here's a short and sweet version of what I'm dealing with
test.h
Class test
{
private:
Vector<Sprite> sprites;
public:
test(item _something);
}
test.cpp
test::test(item _something);
{
sprites.emplace_back(_device, tBank["TestTexture"]);
}
main.cpp
test testItem;
main()
{
testItem = testItem(something);
// This is where the destructor for sprite is called
}
I know the code above doesn't work but it's a shorthand of what is going on. I can post the whole thing if requested. Anyway am I doing something crazy?
First off, I assume with testItem(something) you actually mean test(something) (there are a number of other obvious errors, e.g., main() need to to return int, i.e., it seems this isn't the real code).
When you assign the temporary created with test(something) to testItem the object is copy or move assigned to testItem and, next, the temporary is destroyed. The compiler doesn't have much choice to do otherwise. The contained std::vector<Sprite> can be moved if there is no copy constructor or copy assignment in your test class. Since that isn't the real code, it's hard to tell.
What you are experiencing is expected:
Type t;
t = Type(arg);
The second line creates an object of type Type with the given arguments, it then assigns it to the t variable. At the end of the complete expression, the temporary is destroyed.
here is my c++ code :
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
it returns me the output like :
Say i am in someFunc
Null pointer assignment(Run-time error)
here As the object is passed by value to SomeFunc the destructor of the object is called when the control returns from the function
should i right ? if yes then why it is happening ? and whats the solution for this ???
Sample is passed by value to SomeFunc, which means a copy is made. The copy has the same ptr, so when that copy is destroyed when SomeFunc returns, ptr is deleted for both objects. Then when you call PrintVal() in main you dereference this invalid pointer. This is undefined behavior. Even if that works then when s1 is destroyed ptr is deleted again, which is also UB.
Also, if the compiler fails to elide the copy in Sample s1= 10; then s1 won't even be valid to begin with, because when the temporary is destroyed the pointer will be deleted. Most compilers do avoid this copy though.
You need to either implement copying correctly or disallow copying. The default copy-ctor is not correct for this type. I would recommend either making this type a value type (which holds its members directly rather than by pointer) so that the default copy-ctor works, or use a smart pointer to hold the reference so that it can manage the by-reference resources for you and the default copy-ctor will still work.
One of the things I really like about C++ is that it's really friendly toward using value types everywhere, and if you need a reference type you can just wrap any value type up in a smart pointer. I think this is much nicer than other languages that have primitive types with value semantics but then user defined types have reference semantics by default.
You usually need to obey the Rule of Three since you have an pointer member.
In your code example to avoid the Undefined Behavior you are seeing:
Replace the need to in first statement by must.
Since SomeFunc() takes its argument by value, the Sample object that you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.
Since Sample has no copy constructor defined, its compiler-generated copy constructor simply copies the pointer value, so both Sample instances point to the same int. When one Sample (the temporary copy) is destroyed, that int is deleted, and then when the second Sample (the original) is destroyed, it tries to delete the same int again. That's why your program crashes.
You can change SomeFunc() to take a reference instead, avoiding the temporary copy:
void someFunc(Sample const &x)
and/or you can define a copy constructor for Sample which allocates a new int rather than just copying the pointer to the existing one.
When you pass the argument for the function it's called the copy constructor, but you don't have one so the pointer is not initialised. When it exits the function, the object is calls the destructor to delete the unitialised pointer, so it thows an error.
Instead of
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
try to use
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}
#include <iostream>
#include <memory>
class test
{
private:
int x , y;
public:
test(int a , int b):x(a),y(b){}
void fun()
{
std::cout<< x<<" "<<y<<" "<<std::endl;
}
};
void show(std::auto_ptr<test> t1)
{
t1->fun();
}
int main()
{
show(new test(3,4));
}
I am getting a compilation error , please tell me what's wrong in this code?Thanks in advance.
Whenever you dynamically allocate an object, you should create a named smart pointer that immediately takes ownership of the object, then use that named smart pointer. For example,
std::auto_ptr<test> ptr(new test(3, 4));
show(ptr);
You cannot pass new test(3, 4) directly to the function because std::auto_ptr objects must be explicitly constructed; it would be quite unexpected if a smart pointer took ownership of an object implicitly.
That said, this is rather unusual anyway because when you call show(), the auto_ptr is copied and when auto_ptr is "copied," the original loses ownership and the copy gains ownership (so, after show() is called, you will find that ptr no longer has ownership of the object.
James explained how to resolve the problem.
But the reason auto_ptr was designed so that you can not do this:
show(new test(3,4));
Is because this is a bad idea.
Even this (if it were allowed):
show(std::auto_ptr<test>(new test(3,4)));
Would be a bad idea.
So you ask why.
Well in the normal situation not a big deal.
Bu what happens when you have a function that takes more than one parameter.
show2(std::auto_ptr<test>(new test(3,4)), SomeObject());
Now the standard gurantees that all parameters will be fully evaluated before the call (even the construction of the auto_ptr). But it does not guarantee the evaluation order nor that the evaluation will not be interleaved.
Thus it is possible for this evaluation:
// Phsedu code for parameter evaluation
test* tmp1 = new test(3,4);
SomeObject const& tmp2 = SomeObject();
std::auto_ptr<test> const& tmp3(tmp1);
call(tmp3, tmp1)
This order is bad. Because if the constructor of SomeObject throws an exception you will leak tmp1 as it has not yet been assigned to the std::auto_ptr.
This is why we auto_ptr was designed so that you have to give it a named variable.
std::auto_ptr<test> tmp3(new test(3,4));
SomeObject tmp1;
call(tmp3, tmp1)
Now if SomObject constructor throws the test object will be tidied up.
Apologies if the question sounds silly, I was following experts in SO and trying some examples myself, and this is one of them. I did try the search option but didn't find an answer for this kind.
class A
{
public:
A(){cout<<"A Contruction"<<endl;}
~A(){cout<<"A destruction"<<endl;}
};
int main()
{
vector<A> t;
t.push_back(A()); // After this line, when the scope of the object is lost.
}
Why is the destructor of the class called twice ?
To add the element a copy constructor is invoked on a temporary object. After the push_back() the temporary object is destroyed - that't the first destructor call. Then vector instance goes out of scope and destroys all the elements stored - that's the second destructor call.
This will show you what's happening:
struct A {
A() { cout << "contruction\n"; }
A(A const& other) { cout << "copy construction\n"; }
~A() { cout << "destruction\n"; }
};
int main() {
vector<A> t;
t.push_back(A());
}
The destructor is called once when the temporary sent to push_back is destroyed and once when the element in t is destroyed.
There are two destructor calls because there are two objects: the argument to push_back, and the newly added element within vector t.
STL containers store copies. In your example the element added to the vector by push_back is copy constructed from the argument passed to push_back. The argument is A(), which is a temporary object, see here (variant 4).
Expanding the answer a bit, altough you havent explicitely asked for it: It might be useful to know when the temporary is destroyed. The standard (N4140) sais it pretty clearly in 12.2 p3:
... Temporary objects are destroyed as the last step in evaluating the
full-expression (1.9) that (lexically) contains the point where they
were created...
Side note: If you use emplace_back there is only one object. The new element in the container is directly constructed from the arguments to emplace_back. Many STL container learned an emplace variant in C++11.
Most probably, copy of your object is getting created. Because of which, the destructor for the copied-object, and for the original-object makes the call-count=2.
Example: Even though, you are passing the object reference, to some class, this internally would invoke the copy-constructor. To avoid this, the child-class (to which you are passing the parent reference, must be as;
Parent *const &p parentRef; //Child.h
Then, the parent object will be passed as;
// Parent.cpp
Parent *parentObj = this;
Child *childObj = Child(parentObj);
Additionally, you can debug the copy-constructor invokation, by overriding;
Parent(const Parent& object){
cout <<"copy called.." << endl;
}
...
More info #stackoverflow#