I've got a class named Area and when I create an Area object I need to keep its address. So in Area's constructor I use the following command:
Area *p = this->Area;
and I get an error saying:
"invalid use of Area::Area".
Any idea of what's going wrong?
this is already a pointer to that object. So you should make something like this:
Area *p = this;
The this pointer is an implicit parameter to all member functions (non-static members). Therefore, inside a member function, this may be used to refer to the invoking object.
I create an Area object I need to keep its address.
Both self-reference and self-ptr may be initialized in the initializer list of the ctor. (and it is also easy to do in a method)
class Area
{
private:
Area& selfRef; // size is 8 bytes
Area* selfPtr; // size is 8 bytes - but why bother, just use this
char data[1000]; // size is 1000 bytes
public:
Area() : selfRef(*this), selfPtr(this)
{
for (int i=0; i<1000; ++i) data[i] = 0; // initialize data
};
void foo() {
// easy to do in a method:
Area& localSelfRef = *this; // 8 bytes
// ...
localSelfRef.bar(); // instead of ptr
this->bar(); // direct use of this ptr
selfRef.bar(); // use of class initialized selfRef
}
void bar() {
// ...
}
}
Class size is 1000+ bytes.
selfPtr and SelfRef and localSelfRef are each 8 bytes (on my system).
Related
I was trying a random code to accept values using dynamic size. Surprisingly the for loop in the Accept function does not execute. Instead, the control directly leaves the function. Please explain what is the mistake here?
using namespace std;
#include<iostream>
class consequtive
{
public : int *ptr;
int size;
public :
consequtive(int size);
void Accept();
};
consequtive::consequtive(int size)
{
ptr = new int[size];
}
void consequtive :: Accept()
{
cout<<"Enter elements :: "<<endl;
for(int i = 0 ; i < size ; i++)
{
cin>>ptr[i];
}
}
int main()
{
int size = 0;
cout<<"Enter size ::";
cin>>size;
consequtive obj(size);
obj.Accept();
}
A few problems here.
You have a class parameter that has the same name as a member, which isn't really a problem, but is a source of confusion (As in your case).
You never set the member size to anything inside the constructor.
For number one, I would recommend renaming the class member size to size_ or something similar, since this creates a separation and makes the variables easier to distinguish from each other. As for as the second problem, I would change your constructor to the following:
consequtive::consequtive(int size) : size_(size) // Assuming the member is called `size_`
{
ptr = new int[size];
}
The code should work now, and uses a concept called member initializer lists. Not setting the variable size results in undefined behavior.
You forgot to initialize the size member variable.
You could do something like this:
consequtive::consequtive(int size)
: size(size),
ptr(new int[size])
{
}
You should also add a destructor to your class, to avoid a memory leak:
consequtive::~consequtive()
{
delete[] ptr;
}
This size in the class definition
public : int *ptr;
int size;
this size in the constructor implementation
consequtive::consequtive(int size)
and this size in the main function
int size = 0;
are all different variables. The latter two will both have the same value because of the way they are used, but one size can be changed to a different value without the other being aware. The bug in the asker's code is because the first size is never given a value and is used uninitialized.
Solution:
consequtive::consequtive(int size): ptr(new int [size]), size(size)
{
}
Here we are using the Member Initializer List. We don't gain much from its use in this case, but it is a very useful tool. More on that here: Why should I prefer to use member initialization list?
Be cautious when using a parameter or local variable with the same name as a member. The inner most identifier always wins so inside
consequtive::consequtive(int size): ptr(new int [size]), size(size)
{
// in here
}
the size variable is the parameter and not the member. You can this->size to explicitly state you want the member, but it is a better idea to not reuse the identifier at all. You could forget to prepend this-> and the compiler is unlikely to warn you of the mistake.
The C++ compiler I'm using is an older version (C++98 maybe?)
I can NOT dynamically allocate memory from the system pool using things like new, malloc
I can however use built-in OS calls to malloc from a heap array defined by me.
I'm running into some strange behavior (program crashes) when I do the following
class cBaseClass /* pure abstract */
{
public:
virtual void ifFunc( void ) = 0;
virtual ~cBaseClass() = 0;
}
inline cBaseClass::~cBaseClass()
{
}
class cDclass:cBaseClass
{
public:
cDclass();
~cDclass();
void ifFunc( void ); /* implement the pure virtual */
}
cDclass::cDclass( void )
{
printf("[0x%X] derived constructor called\n", this);
}
cDclass::~cDclass( void )
{
printf("[0x%X] derived destructor called\n", this);
}
void cDclass::ifFunc(void)
{
printf("[0x%X] ifFunc called from derived class\n", this);
}
uchar_t myHeap[4096];
int main ( void )
{
cDclass* pMyPtr = NULL;
uint32_t i = 0;
( void ) memset( myHeap, 0, sizeof(myHeap)/sizeof(myHeap[0]);
for( i = 0; i < 20; i++)
{
pMyPtr = myHeap[i * sizeof(cDclass) + 4];
*pMyPtr = cDclass();
pMyPtr->ifFunc(); /* Crash */
}
}
What I see is that the constructor for the derived class gets called..then its destructor gets called and then a crash.
Am I mistaken in believing that *pMyPtr = cDclass() constructs a class and then makes a copy of that class at the address specified by pMyPtr?
I say this because when I remove
pMyPtr = cDClass()
and create a dummy variable to store an instance of cDclass and then use memmove it no longer crashes.
The first weird thing is that this line:
pMyPtr = myHeap[i * sizeof(cDclass) + 4];
compiles without complaint. It's implicitly converting a uchar_t to a cDclass*, which shouldn't be possible without a reinterpret_cast. But it could be that your compiler is more lenient there. Anyway, at least you're missing a & operator here.
The second problem is that yes, you are wrong in your assumption. What the line does is construct a temporary object on the stack, then assume that at the pointer location there is already a fully constructed object, call that object's compiler-generated copy assignment operator with the temporary as an argument, then destroy the temporary.
The thing that never happens is that an object is actually constructed in the memory. This means the vptr is never initialized, so the call to the virtual function is a null dereference.
What you need to do is use placement-new to construct an object in-place. Your loop should look like this:
int main ( void )
{
uint32_t i = 0;
( void ) memset( myHeap, 0, sizeof(myHeap)/sizeof(myHeap[0]);
for( i = 0; i < 20; i++)
{
// get the address to construct the object at
uchar_t* pMyAddr = &myHeap[i * sizeof(cDclass) + 4];
// construct a new object in-place at that address
cDclass* pMyPtr = new (pMyAddr) cDclass();
pMyPtr->ifFunc(); /* Don't crash */
}
}
Note that you will be responsible for actually calling the destructor for all the objects you created.
*pMyPtr = cDclass();
Assumes that a valid object already exists at *pMyPtr and uses its assignment operator. (On a typical implementation, this is probably not good enough because it doesn't copy the vptr.)
What you need instead is
new(pMyPtr) cDclass;
to call the constructor at a specified memory location. You'll need to #include <new>.
Given a C++ class with assorted member data values and a static int counter, I'd like to have a clear() function that can walk all the elements of an array of these class objects clearing their data members.
So, for example, a class that looks like this and holds a chip's version information (yes, I know I probably need more setters and getters):
class __STA_version_t
{
public:
__STA_version_t() { count++; };
~__STA_version_t() {};
void setVerString( char* x ) { strncpy( verString, x, sizeof(verString)); verString[sizeof(verString)-1] = 0
void clearVerString() { memset( verString, 0x0, sizeof(verString) ); }
char* getVerString() { return verString; }
bool hasVersion() { return verString[0]; }
void clear()
{
for ( int i = 0; i < count; i++ )
{
// what goes here?
}
}
private:
static int count; // how many of these objects exist, need to know for clear().
char verString[20]; // station version as a string
UINT8 major_ver; // major version identifier (3 bits)
UINT8 minor_ver; // minor version identifier (6 bits)
UINT8 revision; // revision identifier (4 bits)
UINT8 chip_ident; // target chip identifier (3 bits)
};
Elsewhere initialize count thusly:
__STA_version_t::count = 0;
Now, create an array of there objects:
__STA_version_t versions[10];
First, just checking, count should equal 10 after this instantiation, right?
In the clear() function, I'd like to say something like:
this[i]->clearVerString();
this[j]->revision = 0;
// etc.
to clear each data member of each element of the array.
Can this be made to work? How?
The issue is that the class can't see outside its boundaries and the container is outside of the class' boundary.
You should use a standard container. Make the clear method clear data members in the class.
The standard containers have methods for determining the number of items.
See std::vector, std::list, std::map, etc.
What you are trying to do is not very "object oriented" IMO. I would argue that the class clear() member function you are trying to implement here should only clear the data of the instantiated object on which it is invoked. What you are trying to do is clear the data in all instantiations of your class, via calling clear() on any/one of them only?
A better approach here would be to store your objects in a std::vector<__STA_version_t>, and then write a static function on your class that either takes the vector as a parameter (ideally), or can access it globally somehow, called maybe clearAll(). Have that function iterate through the vector and call clear() on each object in the vector. The clear() function would then simply call clearVerString() etc on itself - eg:
this->clearVerString();
this->revision = 0; and so on (noting that you don't actually need to use the this pointer if you don't want to).
I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(¤tThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int ¤tThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int ¤tThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int ¤tThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int ¤tThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.
When I allocate a single object, this code works fine. When I try to add array syntax, it segfaults. Why is this? My goal here is to hide from the outside world the fact that class c is using b objects internally. I have posted the program to codepad for you to play with.
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a *s;
public:
// PROBLEMATIC SECTION
c() { s = new b[10]; } // s = new b;
void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
~c() { delete[] s; } // delete s;
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}
Creating an array of 10 b's with new and then assigning its address to an a* is just asking for trouble.
Do not treat arrays polymorphically.
For more information see ARR39-CPP. Do not treat arrays polymorphically, at section 06. Arrays and the STL (ARR) of the CERT C++ Secure Coding Standard.
One problem is that the expression s[i] uses pointer arithmetic to compute the address of the desired object. Since s is defined as pointer to a, the result is correct for an array of as and incorrect for an array of bs. The dynamic binding provided by inheritance only works for methods, nothing else (e.g., no virtual data members, no virtual sizeof). Thus when calling the method s[i].m() the this pointer gets set to what would be the ith a object in the array. But since in actuality the array is one of bs, it ends up (sometimes) pointing to somewhere in the middle of an object and you get a segfault (probably when the program tries to access the object's vtable). You might be able to rectify the problem by virtualizing and overloading operator[](). (I Didn't think it through to see if it will actually work, though.)
Another problem is the delete in the destructor, for similar reasons. You might be able to virtualize and overload it too. (Again, just a random idea that popped into my head. Might not work.)
Of course, casting (as suggested by others) will work too.
You have an array of type "b" not of type "a" and you are assigning it to a pointer of type a. Polymorphism doesn't transfer to dynamic arrays.
a* s
to a
b* s
and you will see this start working.
Only not-yet-bound pointers can be treated polymorphically. Think about it
a* s = new B(); // works
//a* is a holder for an address
a* s = new B[10]
//a* is a holder for an address
//at that address are a contiguos block of 10 B objects like so
// [B0][B2]...[B10] (memory layout)
when you iterate over the array using s, think about what is used
s[i]
//s[i] uses the ith B object from memory. Its of type B. It has no polymorphism.
// Thats why you use the . notation to call m() not the -> notation
before you converted to an array you just had
a* s = new B();
s->m();
s here is just an address, its not a static object like s[i]. Just the address s can still be dynamically bound. What is at s? Who knows? Something at an address s.
See Ari's great answer below for more information about why this also doesn't make sense in terms of how C style arrays are layed out.
Each instance of B contains Both X data member and the "vptr" (pointer to the virtual table).
Each instance of A contain only the "vptr"
Thus , sizeof(a) != sizeof(b).
Now when you do this thing : "S = new b[10]" you lay on the memory 10 instances of b in a raw , S (which has the type of a*) is getting the beginning that raw of data.
in C::m() method , you tell the compiler to iterate over an array of "a" (because s has the type of a*) , BUT , s is actualy pointing to an array of "b". So when you call s[i] what the compiler actualy do is "s + i * sizeof(a)" , the compiler jumps in units of "a" instead of units of "b" and since a and b doesn't have the same size , you get a lot of mambojumbo.
I have figured out a workaround based on your answers. It allows me to hide the implementation specifics using a layer of indirection. It also allows me to mix and match objects in my array. Thanks!
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a **s;
public:
// PROBLEMATIC SECTION
c() { s = new a* [10]; for(int i = 0; i < 10; i++) s[i] = new b(); }
void m() { for(int i = 0; i < 10; i++) s[i]->m(); }
~c() { for(int i = 0; i < 10; i++) delete s[i]; delete[] s; }
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}