Thread: Integer Emulation

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Bah.
    The compiler and I seem to be at odds. Implementation is done. Now it's the testing stage.
    In the following,

    Code:
    TT TNewT CThreadCPPType<T> CThreadCPPType<T>::operator + (const NewT Data) const
    {
    	Lock();
    	CThreadCPPType<T> Temp = CCPPType::operator + (Data);
    	Unlock();
    	return Temp;
    }
    The compiler should call CThreadCPPType(const CThreadCPPType<T>&) to construct a temporary object to return. However, this is also where the error lies. It generates a built-in constructor for it, which means it will not initialize the critical section and therefore crash.
    But I seem to have added overloads for all necessary constructors:

    Code:
    	CThreadCPPType();
    	explicit CThreadCPPType(bool bLogging);
    	TNewT CThreadCPPType(NewT NewData, bool bLogging = false);
    	TNewT CThreadCPPType(const CCPPType<NewT>& Data);
    	TNewT CThreadCPPType(const CThreadCPPType<NewT>& Data);
    Indeed, when looking at the assembly, I can clearly see that it's calling the function:
    Code:
    CThreadCPPType<int>::CThreadCPPType<int>(const CThreadCPPType<int> &)
    Yet the compiler will not call my constructor.
    I've also found that it will call one of these constructors if they exist:
    Code:
    	CThreadCPPType(const CThreadCPPType<int>&)
    	CThreadCPPType(const CThreadCPPType<T>&)
    But it will never either of these constructors:
    Code:
    TNewT CThreadCPPType(const CCPPType<NewT>& Data);
    TNewT CThreadCPPType(const CThreadCPPType<NewT>& Data);
    The error occurs at the line

    Code:
    	MyInt = MyInt + 100;
    In the test source code.
    I don't know what the heck is going on right now, so I'll keep investigating. But if someone knows, it would spare some headache.

    I'll upload latest source.

    Heh, out of the 21 tests, some still fail:

    Test 1: Success!
    Test 2: Success!
    Test 3: Failure!
    Test 4: Failure!
    Test 5: Failure!
    Test 6: Success!
    Test 7: Success!
    Test 8: Failure!
    Test 9: Failure!
    Test 10: Failure!
    Test 11: Failure!
    Test 12: Failure!
    Test 13: Failure!
    Test 14: Failure!
    Test 15: Failure!
    Test 16: Success!
    Test 17: Failure!
    Test 18: Failure!
    Test 18: Failure!
    Test 19: Failure!
    Test 20: Success!
    Test 21: Failure!
    Last edited by Elysia; 03-17-2008 at 05:51 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #17
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You'll have to specify what the (presumably) macros TT and TNewT actually do, and what the relationship is between CThreadCPPType and CCPPType.

    My guess is that you are either supplying overloaded versions of the constructors (and one of the overloaded versions is being called, rather than the one you expect) or that you have forgotten to supply operator=()'s corresponding to each constructor. It's also possible you have defined some conversion operators, and one of those is being implicitly invoked.

    Also, keep in mind the compiler is not obligated to create temporary objects (the standard explicitly allows a compiler to avoid creating them in some circumstances), so the compiler may be eliminating some of the copy constructor calls you are expecting.

  3. #18
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, if you haven't looked at the source, they are macros defined as:

    Code:
    #define TNewT template<typename NewT>
    #define TT template<typename T>
    And the relation between them is (again from the source), that CThreadCPPType is derived from CCPPType, and is supposed to be a thread-safe version of CCPPType.

    As for the rest...
    A constructor is being called. It's implicitly generated by the compiler because there's no source for it. I used disassembly to see it, and indeed, the compiler was calling a constructor.
    I have some constructors, but for CCPPType and CThreadCPPType, there also matching assignment operators.
    I do have some conversion operators, but again, the compiler isn't calling them because I would see.

    I'm aware that the compiler can avoid temporaries, so long as it doesn't break the code. But as of yet, this is debug, so no ill effects (yet).

    Again, the source is available, so if you feel like it, download it & compile it. I avoided this by providing an overloaded constructor for CThreadCPPType<T>, but it's not an ideal solution.

    UPDATE:
    Class now passes all 42 tests.
    Uploading newest source.
    Some overloads still needs to be made and perhaps more tests added to the testing suite, but I think the class is usable for now.

    Uploading new source. Also uploading Help2.cpp - the test suite. I/O fails for some reason I don't know yet.

    Operators, operators, operators...
    No end in sight...

    UPDATE:
    Been working on that class a long time now. Updated test suite to hopefully do all possible sorts of combinations. All tests pass. So I think that would mean the CCPPType class is done.
    I haven't updated the CThreadCPPType yet.
    Also split both classes into their own files because they were growing too large.

    UPDATE:
    Aha! More missing operators! Add, add, add!
    Last edited by Elysia; 03-17-2008 at 08:47 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #19
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Elysia View Post
    Bug? How do you figure? It's a constructor, so it needs to initialize the critical section.
    Yes, okay so if it is supposed to be a constructor (I hadn't noticed) then there's no point in using the critical section in there. I mean the object doesn't exist yet, so another thread sure as hell cant be trying to simultaneously access it. And since it's supposed to be a constructor, the argument should be a const reference.
    You mean such as
    Code:
    operator + (T, const CDataType<T>& )
    I think?
    Nope:
    Code:
    friend CDataType operator + (const CDataType<T>& , const CDataType<T>& )
    Actually, no, it's not a mistake. There is a word "then" and there is a word "than". If this equals that, then do this. If this is less than that, do this.
    Dunno. I just find making a little descriptive names better. Anyway, I changed them all to "Data" instead.
    Okay then I wont have to switch to talking about lack of constency instead:
    Code:
    	bool operator < (const T MinThanData) const;
    	bool operator > (const T BiggerThanData) const;
    	bool operator <= (const T MinEqualThenData) const; // Odd one out
    	bool operator >= (const T BiggerEqualThanData) const;
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #20
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by iMalc View Post
    Yes, okay so if it is supposed to be a constructor (I hadn't noticed) then there's no point in using the critical section in there. I mean the object doesn't exist yet, so another thread sure as hell cant be trying to simultaneously access it. And since it's supposed to be a constructor, the argument should be a const reference.
    Alright, I guess I'll remove the locks from the constructors then. And all constructors do take a const reference now. Though I'm focusing on the non-thread safe for now. It's better to maintain one until it's finished and then update the thread-safe one.

    Quote Originally Posted by iMalc View Post
    Nope:
    Code:
    friend CDataType operator + (const CDataType<T>& , const CDataType<T>& )
    Hmmm. So all global operators should just be friend class operators then. It seems to work, as well.

    Quote Originally Posted by iMalc View Post
    Okay then I wont have to switch to talking about lack of constency instead:
    Code:
    	bool operator < (const T MinThanData) const;
    	bool operator > (const T BiggerThanData) const;
    	bool operator <= (const T MinEqualThenData) const; // Odd one out
    	bool operator >= (const T BiggerEqualThanData) const;
    Ah, typo!
    But it's gone since long ago anyway
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #21
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> So all global operators should just be friend class operators then.
    They don't need to be if they accomplish their work through the public interface, but there's nothing wrong with making them friends when necessary. You can often implement operator+ in terms of a copy constructor and operator+=, in which case making it a friend isn't necessary:
    Code:
    CDataType<T> operator + (const CDataType<T>& lhs, const CDataType<T>& rhs)
    {
        CDatatype<T> temp(lhs);
        temp += rhs;
        return temp;
    }

  7. #22
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    There's no real need for friends, then, though, seeing as the function can access the contents of the classes fine by utilizing the overloaded implicit conversion operator.
    With the added bonus that if a thread-safe class is added to the non-safe one, it will still lock when returning the value.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #23
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    If you're gonna go to the trouble of creating a numeric class, why not also include the lower & upper bounds for the number?
    I was thinking something like this:
    Code:
    #include <iostream>
    #include <stdexcept>
    
    using namespace std;
    
    template <typename T, T TLowerBound, T TUpperBound>
    class Integer
    {
    public:
    	Integer()
    	:	m_Num( TLowerBound ) {}
    
    	Integer( const T&  value )
    	:	m_Num( value )
    	{
    		if ( (value < TLowerBound) || (value > TUpperBound) )
    		{
    			throw std::out_of_range( "Number is out of range!" );
    		}
    	}
    
    	T LowerBound() const
    	{
    		return TLowerBound;
    	}
    
    	T UpperBound() const
    	{
    		return TUpperBound;
    	}
    
    	T Get() const
    	{
    		return m_Num;
    	}
    
    private:
    	T	m_Num;
    };
    
    int main()
    {
    	Integer<unsigned short,	 0,	10>	UShort;
    	Integer<unsigned int,	 1,	200>	UInt;
    	Integer<unsigned long,	 3,	3000>	ULong;
    	Integer<short,		-1,	40>	Short;
    	Integer<int,		-2,	500>	Int;
    	Integer<long,		-3,	6000>	Long;
    
    	cout << "UShort = "	<< UShort.Get()	<< endl
    		 << "    Range = [" << UShort.LowerBound() << ", " << UShort.UpperBound() << "]" << endl
    		 << "UInt = "	<< UInt.Get()	<< endl
    		 << "    Range = [" << UInt.LowerBound() << ", " << UInt.UpperBound() << "]" << endl
    		 << "ULong = "	<< ULong.Get()	<< endl
    		 << "    Range = [" << ULong.LowerBound() << ", " << ULong.UpperBound() << "]" << endl
    		 << "Short = "	<< Short.Get()	<< endl
    		 << "    Range = [" << Short.LowerBound() << ", " << Short.UpperBound() << "]" << endl
    		 << "Int = "	<< Int.Get()	<< endl
    		 << "    Range = [" << Int.LowerBound() << ", " << Int.UpperBound() << "]" << endl
    		 << "Long = "	<< Long.Get()	<< endl
    		 << "    Range = [" << Long.LowerBound() << ", " << Long.UpperBound() << "]" << endl;
    
    	return 0;
    }
    I don't have time to add all the operators you did, but you get the idea.
    Unfortunately it won't compile for floating point numbers. I think you'd have to pass the Lower/Upper bounds through the constructor for float & double.

  9. #24
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I don't really see any practical use of your attempt at thread safetey for this class.
    Though x += 1; is fine, something simple like x = x + 1; is still not at all threadsafe. To get such a thing to be threadsafe you'd have to delve into expression templates I think.

    The ambiguity problems you were having are generally caused by having and "implicit conversion operator". You'd be better off removing that and making an accessor method, such that you would then use friend binary operators. It's for exactly the same reasons std::string has a .c_str() method.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #25
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by cpjust View Post
    If you're gonna go to the trouble of creating a numeric class, why not also include the lower & upper bounds for the number?
    FWIW, I've written one of those already.

    I don't have time to add all the operators you did, but you get the idea.
    Unfortunately it won't compile for floating point numbers. I think you'd have to pass the Lower/Upper bounds through the constructor for float & double.
    You certainly can't use floating point numbers as template arguments. However you can provide integer numerator and denominator values for the upper and lower values with a similar thing for float types. It's not as nice to specify, but you can achieve the same compile-time effect.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  11. #26
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by cpjust View Post
    If you're gonna go to the trouble of creating a numeric class, why not also include the lower & upper bounds for the number?
    I was thinking something like this:
    Sure, I could do that. But I'm not really sure for what purpose there is to limit the range of a number?

    Quote Originally Posted by iMalc View Post
    I don't really see any practical use of your attempt at thread safetey for this class.
    Though x += 1; is fine, something simple like x = x + 1; is still not at all threadsafe. To get such a thing to be threadsafe you'd have to delve into expression templates I think.
    I wouldn't say it isn't safe, since it will lock for operator +, adding one, and then lock for operator = when putting the number inside the class. Sure, it can be a lot of locking, but if you aren't worried about performance, I would think it's a lazy solution to thread safety. Otherwise you'd have to lock manually when reading/writing to the number.

    The ambiguity problems you were having are generally caused by having and "implicit conversion operator". You'd be better off removing that and making an accessor method, such that you would then use friend binary operators. It's for exactly the same reasons std::string has a .c_str() method.
    Yes, they may cause some problems, but I like them. And the problem I was having was not related to the implicit conversion operator.
    Seeing as it's supposed to be a shared class, I could add a method to get the number, and if you wanted to use the class, you could just comment out the implicit operator if you wanted. Some may like it, including me.
    Last edited by Elysia; 03-18-2008 at 03:04 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #27
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Elysia View Post
    Sure, I could do that. But I'm not really sure for what purpose there is to limit the range of a number?
    Well most numbers begin and end on values that don't usually reflect real life situations.
    0-255, 0-65535...

    Some exaples would be:
    Age cannot be negative; Speed cannot be negative and nothing can travel faster than the speed of light (yet); There are 60 seconds in a minute, 60 minutes in an hour, 24 hours in a day...

  13. #28
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I see your point.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #29
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Elysia View Post
    I wouldn't say it isn't safe, since it will lock for operator +, adding one, and then lock for operator = when putting the number inside the class. Sure, it can be a lot of locking, but if you aren't worried about performance, I would think it's a lazy solution to thread safety. Otherwise you'd have to lock manually when reading/writing to the number.
    Okay, well lets just say I wouldn't want to use it with return x = x - 1; instead of InterlockedDecrement for guarding the reference count of a smart pointer, or two threads may both try and free the object.
    My point is that the operation isn't atomic, due to the fact that you lock and unlock twice. Once around the reading, and once around the writing, and it could get changed in between.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  15. #30
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ah, I see it now. Perhaps it might be an idea to derived from a CCriticalSection or such instead, then use a macro to lock, perform the expression, unlock.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. memory issue
    By t014y in forum C Programming
    Replies: 2
    Last Post: 02-21-2009, 12:37 AM
  2. Link List math
    By t014y in forum C Programming
    Replies: 17
    Last Post: 02-20-2009, 06:55 PM
  3. Looking for constructive criticism
    By wd_kendrick in forum C Programming
    Replies: 16
    Last Post: 05-28-2008, 09:42 AM
  4. No Match For Operator+ ???????
    By Paul22000 in forum C++ Programming
    Replies: 24
    Last Post: 05-14-2008, 10:53 AM
  5. load gif into program
    By willc0de4food in forum Windows Programming
    Replies: 14
    Last Post: 01-11-2006, 10:43 AM