After read Inside the C++ Object Model, I try to call member function from vptr.
I found the following situation by accident
gcc version 9.2.0 (tdm64-1)
#include <iostream>
class Foo;
Foo* foo;
class FooBase
{
public:
virtual void Bar1(){};
virtual void Bar2(){};
};
class Foo : FooBase
{
public:
void Bar1()
{
if (this == nullptr)
{
std::cout << "this == nullptr in Bar1" << std::endl;
}
else
{
std::cout << "this == " << this << " in Bar1" << std::endl;
std::cout << "foo == " << foo << " in Bar1" << std::endl;
}
std::cout << "Bar1" << std::endl;
}
};
int main()
{
foo = new Foo;
// std::cout << "foo == " << foo << " in main" << std::endl;
int* vptr = reinterpret_cast<int*>(foo);
int* bar1_ptr = reinterpret_cast<int*>(*vptr);
typedef void (*Func1)();
typedef void (*Func2)(Foo*);
Func1 bar10 = (Func1)*bar1_ptr;
Func2 bar11 = (Func2)*bar1_ptr;
bar10(); // sometimes 'this == 0xffffffff in Bar1'
bar11(nullptr); // this == nullptr in Bar1
return 1;
}
When I comment std::cout << "foo == " << foo << " in main" << std::endl;
the output is
this == 0x96ae0 in Bar1
foo == 0x96ae0 in Bar1
Bar1
this == nullptr in Bar1
Bar1
But when I uncomment std::cout << "foo == " << foo << " in main" << std::endl;
the output is
foo == 0x1d6ae0 in main
this == 0xffffffff in Bar1
foo == 0x1d6ae0 in Bar1
Bar1
this == nullptr in Bar1
Bar1
Q1: Why this pointer has a default value foo == this?
Q2: Why this pointer was changed after uncomment?
When you access Bar1 via Func1, this ends up being whatever was on the stack in the first arg's position. It wasnt a default value - it just happened to be there from your previous calls.
No surprise that the stack can change with change to previous calls.
As you probably found out, calling a class member functions can be implemented as a regular function that takes a class pointer as an argument. In your compiler and case, it looks as though the following are equivalent.
foo->Bar1();
bar11(foo);
Related
is there any mechanism with elegant API to handle functions of any type?
I mean a class that automagically detects type of a function (its return type, arguments, if it is a class member, a const etc), something that I could easily use to handle any kind of events, like in the example below:
class Abc
{
public:
void aFunc() { std::cout << "a()" << std::endl; }
void cFunc(int x, char y) { std::cout << "c(" << x << ", " << y << ")" << std::endl; }
};
void bFunc(int x) { std::cout << "b(" << x << ")" << std::endl; }
int main()
{
Abc abc;
EventHandler a = abc.aFunc;
EventHandler b = bFunc;
EventHandler c = abc::cFunc;
a();
b(123);
c(456789, 'f');
std::cout << "Done." << std::endl;
return 0;
}
The std::function and std::bind can be used internally, but the bind should be done automatically.
here is my code snippet:
#include <iostream>
#include <list>
#include <memory>
class A
{
public:
int a = 100;
A()
{
std::cout << "Create A" << std::endl;
}
~A()
{
std::cout << "Release A" << std::endl;
}
virtual void printer() = 0;
};
std::list<std::shared_ptr<A>> arr;
class B : public A
{
public:
int b = 1000;
~B()
{
std::cout << "Release B" << std::endl;
}
void printer() override
{
std::cout << "B's printer" << std::endl;
}
B()
{
std::shared_ptr<A> tmp(this);
arr.push_back(tmp);
(*arr.begin())->printer();
std::cout << "inside B's c'tor test B counts: " << tmp.use_count()
<< std::endl;
}
};
int main(int argc, char const *argv[])
{
std::shared_ptr<B> B_ptr = std::make_shared<B>();
std::shared_ptr<A> A_ptr(B_ptr);
std::cout << "list address: " << (*arr.begin()).get() << std::endl;
std::cout << "test B address: " << B_ptr.get() << std::endl;
std::cout << "test A address: " << A_ptr.get() << std::endl;
std::cout << "list counts: " << (*arr.begin()).use_count() << std::endl;
std::cout << "test B counts: " << B_ptr.use_count() << std::endl;
std::cout << "test A counts: " << A_ptr.use_count() << std::endl;
return 0;
}
My expectation is: A's reference count should be three, but only got 2. I think when I push_back to the list, there should be a temporarily created share_ptr object, even it is get destroyed, the one in list should also pointing to the same address as A_ptr and B_ptr. It turns out that they (those three), did pointing at the same address, but use_count got different results. (*arr.begin()).use_count() is 1, the others are both 2.
Why? Please help.
Ps: I know turning this pointer to share_ptr is stupid operation, but the result doesn't make sense and even disobey the syntax.
My expectation is: A's reference count should be three, but only got 2.
Your expectation is wrong. You only made one copy of the shared pointer, so the use count is 2.
std::shared_ptr<A> tmp(this);
On this line you transfer the ownership of a bare pointer that you don't own into a new shared pointer. Since this was already owned by another shared pointer, the behaviour of the program will be undefined when the two separate owners attempt to destroy it.
Creating a shared pointer from this is possible using std::enable_shared_from_this, but it's not simple.
I'm using Visual Studio 2017 and came across a bug which I cannot understand. I have this code as an example:
#include <iostream>
struct Foo
{
int a = 0;
int c;
int *b;
Foo(int n)
{
a = n;
b = &c;
}
};
struct Bar
{
Foo nestedFoo = Foo(0);
Bar(int n)
{
std::cout << "bar constructor nestedFoo before:" << std::endl;
std::cout << &nestedFoo.a << std::endl;
std::cout << nestedFoo.b << std::endl;
nestedFoo = Foo(n);
std::cout << "bar constructor nestedFoo after:" << std::endl;
std::cout << &nestedFoo.a << std::endl;
std::cout << nestedFoo.b << std::endl;
}
};
struct App
{
Bar bar = Bar(2);
};
int main()
{
App app;
Bar bar = Bar(10);
Foo foo = Foo(5);
std::cout << "foo before:" << std::endl;
std::cout << &foo.a << std::endl;
std::cout << foo.b << std::endl;
foo = Foo(20);
std::cout << "foo after:" << std::endl;
std::cout << &foo.a << std::endl;
std::cout << foo.b << std::endl;
std::cout << "bar.nestedFoo:" << std::endl;
std::cout << &bar.nestedFoo.a << std::endl;
std::cout << bar.nestedFoo.b << std::endl;
std::cout << "app.bar.nestedFoo:" << std::endl;
std::cout << &app.bar.nestedFoo.a << std::endl;
std::cout << app.bar.nestedFoo.b << std::endl;
return 0;
}
I expected the pointer and the address of the member to be the same after the reassignment but it seems this is not the case, &Foo.a and Foo.b have different values:
bar constructor nestedFoo before:
0058FEE8
0058FEE8
bar constructor nestedFoo after:
0058FEE8
0058FC24
bar constructor nestedFoo before:
0058FED8
0058FED8
bar constructor nestedFoo after:
0058FED8
0058FD04
foo before:
0058FEC8
0058FEC8
foo after:
0058FEC8
0058FDF8
bar.nestedFoo:
0058FED8
0058FD04
app.bar.nestedFoo:
0058FEE8
0058FC24
At first I thought it only happened when I had Foo as a member of another struct, but it seems to happen even at a top-level assignment. So what am I doing wrong?
Any help will be appreciated, thank you!
Edit: showing that assigning b to &c which is a member that doesn't get (explicitly) reassigned also doesn't work.
This question already has answers here:
Two calls to destructor
(3 answers)
Closed 4 years ago.
am new to c++ and and trying to learn the cost of copying values or passing references, in my example I found though a segment of code that is for me hard to understand:
consider this example:
struct Foo {
Foo(int x) :
internVal { x } {
std::cout << "Con: " << std::endl;
}
~Foo() {
std::cout << "Des: " << std::endl;
}
int getVal() const {
return internVal;
}
private:
int internVal { 0 };
};
now when I do:
int main(int argc, char **argv) {
{
Foo a { 111 };
Foo b { 6555 };
Foo c { -444 };
std::cout << " Foos created..." << std::endl;
std::vector<Foo> vector_Test { };
vector_Test.push_back(a);
vector_Test.push_back(b);
vector_Test.push_back(c);
std::cout << " Foos added..." << std::endl;
for (const auto& d : vector_Test) {
std::cout << "-----" << d.getVal() << "-----" << std::endl;
}
std::cout << " Foos printed..." << std::endl;
}
std::cout << " Foos out of scope..." << std::endl;
std::cout << "end!" << std::endl;
//
return 0;
}
I see the following output:
Con:
Con:
Con:
Foos created...
Des:
Des:
Des:
Foos added...
-----111-----
-----6555-----
------444-----
Foos printed...
Des:
Des:
Des:
Des:
Des:
Des:
Foos out of scope...
end!
so my question why are more objects destroyed as created?
I would expect an even number... if I create directly/ indirectly 3 objects then destroy 3 objects
Do I habe a memory leak some where?
thanks
Ps: my compiler is MinWG
When you do vector_Test.push_back(a); you are adding a copy of the instance to the vector.
Which means later on those copies and the original elements get destroyed.
When running the following code, it seems that the destructor is running twice. I have a theory that this might have to do with an automatic move constructor being added, but I'm not sure how to test this.
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
destructor: 4
Value is: 4
Value is: 4
destructor: 4
Is this output correct?
std::function works by copying the callable object you provide. There is no copy-elision here, since your lambda is not an std::function but of an anonymous, unrelated type.
Hence, the two destructors you see are:
The Instance member of the original, temporary, lambda;
The Instance member of the copy of the lambda that was stored into the std::function and lived until the end of main.
Ok, I defined the move and copy constructors manually and also saw errors when I instructed the compiler to delete them in a variant of the code below. Everything seems normal.
Revised code:
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
Structure(const Structure& other) :
Value(other.Value) {
std::cout << "copy constructor: " << Value << std::endl;
}
Structure(Structure&& other) :
Value(other.Value) {
other.Value = -1;
std::cout << "move constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
move constructor: 4
destructor: -1
Value is: 4
Value is: 4
destructor: 4