Templates, pointers, syntax issues...

As usual, I have lots of questions. But you can't blame me: if the C++ tutorial answered them (and I think it should, but I don't complain because the tutorial has been very useful to me), I wouldn't need to ask. And I don't have time for experiments (I only try complicated things...simple C++ questions aren't worth the time...I'm just so, so busy...)

1. CBase* obj = new CDerived; works. The pointer doesn't "know" it's actually a CDerived object and not a CBase one, but it can access the members inherited from CBase. The problem is with arrays: CBase* objs = new CDerived [5]; . If the compiler treats objs like any other CBase* pointer, it won't access the elements correctly. Does the compiler follow the allocations and makes objs++; work the same as objs=reinterpret_cast<CDerived*>(objs)+1;?

(More questions will be added later because I have to go now...Rosh Hashana...)

Edit: There are more questions in the third post.
Last edited on
That makes no sense. You only have time to tackle experiments that take a long time, but not for ones that
could take only 5 minutes? Where is the logic in that? Perhaps if you asked the more complicated questions,
you'd free up the time you need to tackle the easy ones.

Anyway.

The answer to your question is no. objs[1] will not access the correct memory location because as far
as the compiler knows, sizeof( objs[0] ) == sizeof( CBase ) and not sizeof( CDerived ).


"That makes no sense" - it does make sense. Asking the complicated questions is like letting you program for me. It's like asking you to write a function for me. But simple questions about the syntax don't require coding because experienced programmers know the answer. What's the point in programming if I let other people solve my problems? It's not fun.

Anyway, I'm adding questions:

2. Let's say I have a class template MyClass<class T> . One of its members is a pointer to another object of this class. Which is correct, MyClass<T>* ptr; or MyClass* ptr; (these are lines from the class declaration)

3. Can an operator function be a template? If yes, can it be a template in which the function parameter types don't depend on the template parameters?

4. Is it possible to have a function template specialization?

5. Can constructors and destructors be defined as inline like this:
1
2
3
4
5
6
7
8
9
10
class MyClass
{
    MyClass();
    /*  . . .   */
};

inline MyClass::MyClass()
{
    /*  . . .  */
}


5. MyClass has an initialization list. The problem is that one of its members is called myvar, and one pf the constructor's parameters is called myvar too. Without initialization lists, the line this->myvar=myvar; (inside the constructor) initializes the member, but does this syntax work with initialization lists to? In other words, do the following pieces of code work:
1
2
3
4
5
6
7
8
class MyClass
{
public:
    int myvar;
    MyClass (int myvar) : myvar(myvar)
    {
    }
};


1
2
3
4
5
6
7
8
class MyClass
{
public:
    int myvar;
    MyClass (int myvar) : this->myvar(myvar)
    {
    }
};


6. Is the destructor executed automatically when an object's scope ends? And if the object is dynamically allocated, is it destroyed only when the program ends independently of the pointer's scope?

7. Do the operators - < > <= >= work with pointers (both operands are pointers)?

8. Is the explicit keyword in the standard or it's a part of Microsoft's extension that works only in Visual C++ ?

9. CBase has a pure virtual function. CDerived has a definition of this function. Does CDerived need to have the function declaration inside the class declaration, like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CBase
{
public:
    virtual void func()=0;
    . . . 
};

class CDerived : public CBase
{
public:
    void func();
    . . . 
};

void CDerived::func()
{
    . . . 
}
Actually, the complicated questions are what you SHOULD ask, so you don't screw them up. And besides, I don't see how you can afford to wait for a forum response when just testing the program would tell you in less time.

[quote]But simple questions about the syntax[/code]

Here is a simple question:
What is the following?
void *(*(*fp1)(int))[10];
2. Either. MyClass* ptr; works just fine.

3. Yes and yes.

4. Yes.

5. Yes.

5 again. The first one.

6. Yes and no, the destructor is run when the pointer is deleted.

7. Yes, but you have to call them like this:
answer = someNum->operator+( *someOtherNum );

8. explicit is standard.

9. Yes.
(((((((((('Actually, the complicated questions are what you SHOULD ask" - you don't understand...I use the internet only on weekends, few hours per week and not every week. So I don't mind waiting for an answer. Anyway I see it a week after I ask, even if the answer is posted five minutes after the question. It's faster that wasting my few weekly hours on experiments (I have few new questions every week...5 minutes of typing them plus 5 minutes reading them and copying the answers to my papers - it's much faster than wasting a whole hour on experiments (and yes, it takes a whole hour. At least. I'm one of those programmers who just can't program without planning. Anyway, even a fast experiment takes 10 minutes, and 9 questions require 9 experiments which would take 90 minutes. And even if they took half, 45 minutes, it's still a lot more than the 10 minutes I need to post a question and get the answer).))))))))))

Anyway, I'm posting again because the answer to question 7 does not fit the question (my fault...). I meant the operations use the pointers themselves, without indirection:
1
2
int a = 1 , b = 2 ;
int *ptr1 = &a , *ptr2 = &b ;


Are the expressions ptr1>ptr2 and ptr1-ptr2 legal?
Are the expressions ptr1>ptr2 and ptr1-ptr2 legal?


Yes, they are legal.
Thanks for the answers! Here come more questions...

1. I don't understand what exactly is going on with 64-bit programming. Some documents say long is 64bit, others say it's 32bit and long long is 64. I'd like to know exactly which name I need to use for a 64-bit integer( In case it varies depending on compiler or OS, I can simple define my own data type and typedef it differently depending on the compiler/OS...)

2. Can a (stand-alone, without any inheritance or polymorphism) class have only function members? If yes, does it have limitations? Which? Or is it just like an object/variable with size of 0 bytes? And can a pointer point to such an object?

3. These is a class template called template<class T> MyClass;. MyClass has a member function called func(). For some types passed as T, I'd like func() to have different implementations, not the general one. The question is whether this code is enough:

1
2
3
4
5
6
7
8
9
10
11
template<class T>
void MyClass<T>::func()
{ 
    /* general implementation */
}

template<>
void MyClass<int>::func()
{
    /* a different implementation specific to T=int */
}


MyClass itself does not have a specialization. It only has the general class definition, while func() has a special definition for int. Is it legal?

4. There is a global pointer int* globPtr;. There is a global function func() that uses a local pointer int* locPtr;. func() does three things: it allocates dynamic memory with locPtr=new int [5];and then copies locPtr into globPtr: globPtr=locPtr;. main() executes func() and then tries to set the dynamic array through b. Will it work or the dynamic memory is freed when func() ends? I'm asking because I got contradicting answers to the question "does dymanic memory get automatically deleted before the program ends". One answer is no, the other is that the memory is deleted when the pointer used with new is deleted/gets out of scope.

5. Is a partial specification of a partial specification allowed? for example, for template<class A, class B, class C> MyClass;, can I define the three different specifications template<int,B,C> , template<int,float,C> and template<int,float,char*> ? Will the compiler recognize which is a specific case of which?

6. Can a typecasting operator function be global or it has to be a member function? And it be a static member? And in general, can operator functions be static members? If yes, are there any limitations or special rules for them?

7. If a class has an operator bool() function, can an object of this class be alone inside an if statement?

8. Can a member of a class template point to another instantiation, for example
template<class T> MyClass having a MyClass<int>* ptr; or template<class T, class U> OtherClass having a OtherClass<U,T>* ptr; , etc. ?

9. There are three floats: a,b, and c. a*b/c gives a result slightly bigger than a*(b/c). Why? Does it mean I should generally try to use division as the last operation whenever possible in order to have minimal round-off?

10. There's template<class T> void func(T arg);. One of the lines inside func() contains the expression arg.MemberFunc(). Does it mean that every class which defines a public member function (either static or non-static) without parameters called MemberFunc() can be passed as T while passing any other class will generate an error?

11. What is "big-endian" and "little-endian" ? Which OS/processors are big-endian and which are little-endian?
1. C++ doesn't force the numeric types to a specific size so you can never be sure of what the result will be ( BTW long long is not part of the current standard )
2. Yes, It shouldn't have limitations, The minimum size fro a type is 1 byte but that may vary depending on the compiler, A pointer can point anywhere
3. That should work, you can completely remove the function from the generic class if you specialize the entire class -adding 'func' for int etc.- instead of specializing just the member function.
4. Dynamic memory in C++ is released only by the programmer
5. You can partially specialize a template but it works as with default arguments with functions, you can have specialized only the last parameters
6. Operators work with specific objects so they can't be static members. The conversion operator has to be a member.
7. Yes
8. Yes
9. Floating point numbers don't have infinite precision so you will never have a 100% accurate result
10. Yes
11. http://en.wikipedia.org/wiki/Endianness
1 - So I'll have to check which compilers support 64-bit long and which support 64-bit long long and use #define or typedef accordingly, using #ifdef _win64 , #ifdef _mach_ ,etc. for every compiler? Or sizeof() can be used with an #if directive? (which would make things easier since then I wouldn't need to find out which constants are defined by each compiler I'd like my code to support)

2 - So some compiler allow such classes and others don't? Does it mean I should generally avoid using such classes?

4 - Someone else said it's automatically released when the program execution ends. And another answer I got is that it's released when the pointer's scope ends. Why is there no one answer (as long as a destructor is automatically executed (at the end of the scope) for a statically-allocated object that has allocated dynamic memory, I'm not worried, but I'm wondering why different people give me different answers...

5 - Why only the last parameters? Remember, I can explicitly specify the template parameters, so why would other specializations not work? For template <class A, class B, class C>, I could write a specialization for template <A,int,C> and then use, for instance, func<float,int,char*> (1.2f,5,text) explicitly instead of just using func(1.2f,5,text). When explicitly specifying parameters, the compiler doesn't need to guess because I tell it which types I'm using.

9 - Okay, but should I generally try to use division as the last operation whenever possible in order to have minimal round-off?

11 - Are there defined constants that let me know the endianness type (little / big) ? Or I'll have to use processor/OS specific constants and define my own IS_LITTLE_ENDIAN constant accordingly?
1- sizeof constants are generated at compile time so you can't use them in preprocessor directives. You can do this checking at runtime but I'd suggest you using a library for numeric time without size limitations (eg GMP ) if you need to hold at least 64-bit integers

2- All compilers support that, I meant that the compiler may do some weird things with the size of classes

4-
Someone else said it's automatically released when the program execution ends.
It may, depending on the compiler and the OS. In most cases it will but you have to release dynamic memory to be 100% sure
And another answer I got is that it's released when the pointer's scope ends.
This is completely wrong.
why different people give me different answers...
It may depend on the language they are used to, in C(++) dynamic memory is released only by the programmer.

5- You can name the parameters how you wish but the compiler doesn't care. You need to be specific when partial specializing.
BTW, I'm not 100% sure on this one


9- If you have operations which guarantee the result to be an integer it may make the difference but if you already have decimal digits it doesn't matter

11- There aren't constants that I know, but you can do some tricks:
1
2
3
4
short s = 1; //use only 1 byte
char *p = (char*)&s;
if ( p[0] ) // first byte -this assumes sizeof(short) > sizeof(char)-
    //little endian 
Anyway, why you care?
Last edited on
thanks for the answers! :)

(About 11 : I care about endianness because some operations, for instance getting a float's or a double's fraction of exponent depend on the order of the bytes. And the trick won't help me because it checks endianness real-time. I need to check it through preprocessor directives.)

( About 9 - it does matter. Sometimes it makes a difference in the last digit.)
Last edited on
4) Because there are two ways to answer the question. Many OSes such as Windows, Unix and BSD equivalents, MacOS, etc have a memory manager. The purpose of a memory manager is to allocate physical pages of memory to a process that requests memory. The OS keeps track of which physical pages of memory are allocated to what process, such that when a process exits--normally or abnormally--all of the physical pages allocated to that process are freed back for use by other processes. This is NOT the same thing as malloc/free or new/delete. The heap is a chunk of memory that is allocated by the C/C++ runtime library from the OS. So the OS knows that the process is now using the memory. The C/C++ runtime then doles out pieces of that memory when malloc or new is called. When free is called (or delete used), the memory is released back to the C/C++ runtime which can then give that same memory out on a subseqent call to malloc (or on a new). Regardless of whether your program correctly frees its memory back to the runtime when it exits, the OS always releases all of the physical pages used by your process. So the answer is yes and no in these OSes. Other OSes (DOS comes to mind) do not have a memory manager, such that if the C/C++ runtime does not explicitly release the memory back to the OS, it remains allocated forever, even after your process exits.

9) Read "What Every Computer Scientist Should Know About Floating Point Arithmetic". There is no simple answer to the question.

Topic archived. No new replies allowed.