www.digitalmars.com         C & C++   DMDScript  

c++ - DMC 8.38n Bug - Static & Template

reply Adrian Boeing <Adrian_member pathlink.com> writes:
There appears to be a bug with DMC in its use of static variables.

This code compiles and works fine with VC6,GCC3.2,and IntelC 7.1:

#include <stdio.h>
#include <vector>
#define VECTOR std::vector

template <typename T>
class A {
public:
void PrintX() {
printf("x size:%d\n",vector().size());
}
static std::vector<T>& vector()
{
static std::vector<T> instance;
return instance;
}
};

template <typename T>
class B {
public: 
void SetA(T &t) {
A<T>::vector().push_back(t);
printf("B::SetA, x size:%d\n",A<T>::vector().size());
}
};

class C : public B<int> {
public:
C() {
printf("C\n");
int val=77;
SetA(val);
}
};

C global_variable_c;

int main() {
C c;
A<int> a;
a.PrintX();
}

The output produced by all other compilers is:
C
B::SetA, x size:1
C
B::SetA, x size:2
x size:2

But for DMC the output is:
C
B::SetA, x size:1
C
B::SetA, x size:1
x size:1

Thanks.
If anyone can tell me a work-around that would also be usefull.

PS:Im not sure where the bug reports are supposed to go. Here?
Nov 18 2003
parent reply "Walter" <walter digitalmars.com> writes:
Yes, this is the right place to report bugs. I'll check it out. -Walter
Nov 19 2003
parent reply Adrian Boeing <Adrian_member pathlink.com> writes:
In article <bpfj9g$2qna$1 digitaldaemon.com>, Walter says...
Yes, this is the right place to report bugs. I'll check it out. -Walter

Hi, I'm just wondering if you've gotten around to looking at this yet? Can anyone suggest a work-around so that the program will run correctly? Is there some method to order the initialization of static variables? (something like #pragma init_seg for MSVC?) Thanks. Here is the example code again: #include <stdio.h> #include <vector> #define VECTOR std::vector template <typename T> class A { public: void PrintX() { printf("x size:%d\n",vector().size()); } static std::vector<T>& vector() { static std::vector<T> instance; return instance; } }; template <typename T> class B { public: void SetA(T &t) { A<T>::vector().push_back(t); printf("B::SetA, x size:%d\n",A<T>::vector().size()); } }; class C : public B<int> { public: C() { printf("C\n"); int val=77; SetA(val); } }; C global_variable_c; int main() { C c; A<int> a; a.PrintX(); } And the correct(ie: what I want) program output: C B::SetA, x size:1 C B::SetA, x size:2 x size:2 But for DMC the output is: C B::SetA, x size:1 C B::SetA, x size:1 x size:1 Thank You!
Dec 28 2003
parent reply dan <dan_member pathlink.com> writes:
Hi, I'm just wondering if you've gotten around to looking at this yet? 

Can anyone suggest a work-around so that the program will run correctly?

Writing it clearly might be a start. Why call a function "PrintX()" when it is printing the size of an array? Wouldn't it make more sense to call it "PrintArraySize()"? One of the most basic principles of good coding is that of separating commands from queries. Queries return a value but are class const. Commands are non-const and return void. And you never write a function that causes side-effects that aren't obvious from the functon name. If you *need* to print from a constructor, such as to have a log of when it executes, it should print something like "class C's default ctor executing", not just "C". As it is, your code is so inscrutable I find it impossible to help you, as I get lost trying to understand it. And no, there is no way to determine the order of static initialization. And there will never be; otherwise we'd have to have a language within the language. What you can do is replace static variables with functions, so that if static int A is defined in terms of static int B, then static int A(){...} can simply call static int B(){...} during its initialization. If B is a constant primitive, like 77, just write it like static int B(){ return 77; } for consistency; and everything will work out; it's called lazy initialization. But it might be a problem when using such "constants" where a compile time constant is needed, such as in sizing an array. Templates might be better in such case, some basic metaprogramming. But in most cases, compile time constants are not needed if the design is done right: Use vector, instead of array, etc. HTH
Dec 28 2003
parent reply Adrian Boeing <Adrian_member pathlink.com> writes:
Hi, Thanks for the reply. (updated code at end)

Writing it clearly might be a start. Why call a function "PrintX()" when it is
printing the size of an array?  Wouldn't it make more sense to call it
"PrintArraySize()"?

Sure, added some clearer code with comments. This code is not the actual code I am trying to use, it is just a simplified version which illustrates the problem. This is why the code appears to do "nothing"
And no, there is no way to determine the order of static initialization. And
there will never be; otherwise we'd have to have a language within the language.

Shame. That could have solved this problem.
What you can do is replace static variables with functions, so that if static
int A is defined in terms of static int B, then static int A(){...} can simply
call static int B(){...} during its initialization. 

This is what I have tried to do, which is why class A's returnvectorinstance simply returns an instance of a static vector. The desired output: class C's default ctor executing class B::AddToVector::Vector size:1 class C's default ctor executing class B::AddToVector::Vector size:2 Vector size:2 DMC's output: class C's default ctor executing class B::AddToVector::Vector size:1 class C's default ctor executing class B::AddToVector::Vector size:1 Vector size:1 Sorry for any confusion caused. Here is the code again: #include <stdio.h> #include <stdlib.h> #include <vector> template <typename T> class A { public: //this displays the number of items in the array static void PrintArraySize() { printf("Vector size:%d\n",returnvectorinstance().size()); } //this should ensure that the vector exists. static std::vector<T>& returnvectorinstance() { static std::vector<T> instance; return instance; } }; template <typename T> class B { public: //this adds an entry to the static vector, in class A void AddToVector(T &t) { A<T>::returnvectorinstance().push_back(t); printf("class B::AddToVector::"); A<T>::PrintArraySize(); } }; class C : public B<int> { public: //C's default ctor adds a value to A's static vector C() { printf("class C's default ctor executing\n"); int val=rand(); AddToVector(val); } }; C global_variable_c; //this variable should add an entry to A's static vector (ie: 1 entry) int main() { C c; //this variable should increment the number of entrys in A's static vector (ie: 2 entries) A<int> a; a.PrintArraySize(); //with VC,gcc,and icc a.PrintArraySize, will print "2". //however, with DMC it will print "1". }
Jan 04 2004
parent reply Arjan Knepper <arjan ask.me> writes:
Well quickly glancing over the code provided, I would say you're right, 
it should return 2.

Have you tried to make 'returnvectorinstance()' _not_ a class member?
e.g:

template < class T > static vector < T >  &returnvectorinstance ()
{
    static vector<T> instance;

    return instance;
}

This should work even with 8.38 (I'm using the same contruct and never 
had troubles)

Arjan Knepper

Adrian Boeing wrote:
 Hi, Thanks for the reply. (updated code at end)
 
 
Writing it clearly might be a start. Why call a function "PrintX()" when it is
printing the size of an array?  Wouldn't it make more sense to call it
"PrintArraySize()"?

Sure, added some clearer code with comments. This code is not the actual code I am trying to use, it is just a simplified version which illustrates the problem. This is why the code appears to do "nothing"
And no, there is no way to determine the order of static initialization. And
there will never be; otherwise we'd have to have a language within the language.

Shame. That could have solved this problem.
What you can do is replace static variables with functions, so that if static
int A is defined in terms of static int B, then static int A(){...} can simply
call static int B(){...} during its initialization. 

This is what I have tried to do, which is why class A's returnvectorinstance simply returns an instance of a static vector. The desired output: class C's default ctor executing class B::AddToVector::Vector size:1 class C's default ctor executing class B::AddToVector::Vector size:2 Vector size:2 DMC's output: class C's default ctor executing class B::AddToVector::Vector size:1 class C's default ctor executing class B::AddToVector::Vector size:1 Vector size:1 Sorry for any confusion caused. Here is the code again: #include <stdio.h> #include <stdlib.h> #include <vector> template <typename T> class A { public: //this displays the number of items in the array static void PrintArraySize() { printf("Vector size:%d\n",returnvectorinstance().size()); } //this should ensure that the vector exists. static std::vector<T>& returnvectorinstance() { static std::vector<T> instance; return instance; } }; template <typename T> class B { public: //this adds an entry to the static vector, in class A void AddToVector(T &t) { A<T>::returnvectorinstance().push_back(t); printf("class B::AddToVector::"); A<T>::PrintArraySize(); } }; class C : public B<int> { public: //C's default ctor adds a value to A's static vector C() { printf("class C's default ctor executing\n"); int val=rand(); AddToVector(val); } }; C global_variable_c; //this variable should add an entry to A's static vector (ie: 1 entry) int main() { C c; //this variable should increment the number of entrys in A's static vector (ie: 2 entries) A<int> a; a.PrintArraySize(); //with VC,gcc,and icc a.PrintArraySize, will print "2". //however, with DMC it will print "1". }

Jan 05 2004
parent Adrian Boeing <Adrian_member pathlink.com> writes:
Hi Arjan,

Thank you, the example you provided works fine.

Hopefully the bug will be fixed anyway.

Cheers,
-Adrian

In article <btc4id$u3$1 digitaldaemon.com>, Arjan Knepper says...
Well quickly glancing over the code provided, I would say you're right, 
it should return 2.

Have you tried to make 'returnvectorinstance()' _not_ a class member?
e.g:

template < class T > static vector < T >  &returnvectorinstance ()
{
    static vector<T> instance;

    return instance;
}

This should work even with 8.38 (I'm using the same contruct and never 
had troubles)

Arjan Knepper

Jan 07 2004