How dangerous is this class exactly?

The Partridge Family were neither partridges nor a family. Discuss.
User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

How dangerous is this class exactly?

Post by cyboryxmen » June 7th, 2016, 2:29 pm

For years now, I've been trying to figure out how to align different objects together in memory. This proved to be impossible since C++ does not allow you to put different objects inside one array. Most people usually do it by having an array of pointers and then using new() to create those objects individually and store their addresses in the pointers. The problem with that solution is that the program can be much more efficient if the data is lined up in a single contiguous block of memory.

So after being inspired after reading up on unions, I created my own union like template class that I call Room. Basically, Room is a Template class that takes 2 datatypes and optionally additional data types as its template parameter.

Code: Select all

template<class FirstType, class SecondType, class...OtherTypes>
class Room;
Room will always be the same size of it's largest datatype. That way, all of it's datatypes can be stored inside it individually. When you store data inside Room with CheckIn(), it will remember what type of data that is occupying it. With the help of EnumClass which is a class that enumerates datatypes, Room can return a number that tells us what the type occupying it is with GetCurrentOccupant(). To access the data, you must call the Visit() function that returns a reference to the data.

Code: Select all

std::size_t GetCurrentOccupant();

template<class Type, bool OverrideIfOccupied = false>
void CheckIn(const Type& type);

template<class Type, bool CheckIfOccupying = true>
Type& Visit();
By passing true to the template parameter CheckIfOccupying, room can check if that is actually the type that is occupying it currently and throws an error if that is not the case. This ensures type safety by making sure that no part of the program is using the data incorrectly forcing the program to check what type of data is occupying it first.

Having this class will open huge possibilities for me in programming. For one thing, I can finally align different datatypes together in one contiguous block of memory by having an array of rooms of those datatypes. I can also use a method of type switching unlike polymorphism where the type is revealed allowing me to add more functionality to the object outside of it. This would be useful for things like rendering codes that would preferably be better written outside of classes like ones derived from the Shape class.

Code: Select all

struct Square
{
    double side;
};

struct Rectangle
{
    double width;
    double height;
};

struct IsosTriangle
{
    double side;
    double top_angle;
};

using ShapeRoom = Room<Square, Rectangle, EquilateralTriangle>

ShapeRoom shape_rooms[20];

//set the data up

void RenderShape(const ShapeRoom& shape_room)
{
    switch(shape_room.GetCurrentOccupant())
    {
        case ShapeRoom::IndexOf<Square>::index:
       {
           //render code
       }
       //other cases
    }
}

void RenderShapes()
{
    for(auto& room : shape_rooms)
    {
        RenderShape(room);
    }
}
Under the hood, Room is actually an array of uint8_t that is the size of it's biggest data type and it uses c style casts to use them as other types. Already, you can see that this may not be a safe way to use data especially if the datatype is polymorphic depending on the compiler's implementation of them. Even if I use it to only store non-polymorphic objects, I still do not know how C++ compilers manage data that well to assume that this won't cause errors. C compilers may have a better time with this since C code does this alot but it may be different for C++ compilers. Just how dangerous is the Room class?
-Zekilk
Zekilk

albinopapa
Posts: 4258
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: How dangerous is this class exactly?

Post by albinopapa » June 7th, 2016, 3:54 pm

I suppose one way of having an array of multiple types of objects is to create an array of structs that hold the different types. However, depending on what you are trying to accomplish, this type of alignment may still not be the most efficient. Going off what you have posted, you understand a union of members share the same memory address, so a union of uint8_t * 8 for instance, would hold:

unsigned/signed char[8]
unsigned/signed short[4]
unsigned/signed int[2]
unsigned/signed long long
float[2]
double

I'm guessing that's one of the reasons you have the enums to check which types are in the union. If you are going to have multiple types in the union and you want them to be packed together you could use a union of types and structs or you could just create an array of type uin8_t and cast addresses in the array to the data types you want.

Code: Select all

// Allocate 1024 bytes
uint8_t *mem_block = std::unique_ptr<uint8_t[]>(new uint8_t[1024]);

int *temp_int_array = static_cast<int*>(mem_block);
for(int i = 0; i < 4; ++i)
{
	temp_int_array[i] = i * 2 + 1;
}

int start_of_next_block = 4 * sizeof(int);
int space_left_in_mem_block = 1024 - start_of_next_block;
float* temp_float_array = static_cast<float*>(&mem_block[start_of_next_block));

for(int i = 0; i < 40; ++i)
{
	temp_float_array[i] = i + 8 / 7;
}

To be honest, a struct is going to be your best route for packing data. Unions have their place I suppose, but I haven't found a good use for them. I have mostly used them for sharing memory between an unsigned int and a struct of unsigned chars.

The only thing about structs/classes, is the order you put the members in. You list the largest data types first. This allows the data to be packed as tight as possible, but there is also the memory alignment of the structure to consider as well. After you pack your data efficiently, if the size of the struct/class is not a multiple of 4 or 8, then there will still be a gap between an array of these data structures.

As far as your question on safety of your class, I've seen other members such as MrGodin use enums to tag objects, that way he can cast pointers to the correct objects, without having to use anything like try/catch for instance. I guess what you need to ask yourself is, what's the goal? If you just want to put data next to each other, use a struct.

There is also a way to check types without having to use enums, but not sure what all compilers support it. It's called Run-time Type Information (RTTI). The program keeps track of data types during run-time, which is normally not the case because it slows down performance a bit.

If you are trying to optimize your program or worried about speed, then be specific in your code. Having a class that does general things is never going to be as fast as a class that does a specific task. Look up structure of arrays (SOA). Basically, your structure would have separate arrays of all the different members of the struct. This is going to be the most efficient since your CPU will be able to cache elements in the array ahead of time while the CPU is processing the data.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

cameron
Posts: 794
Joined: June 26th, 2012, 5:38 pm
Location: USA

Re: How dangerous is this class exactly?

Post by cameron » June 7th, 2016, 3:59 pm

Clever idea you have there. But I cant say much about safety without seeing the implimentation. I have only worked with non contiguous data in the sense of a data block and segmenting it to fit the largest data type. I would be interested in seeing the rest of the implementation. I am curious about the implementation of EnumClass, GetCurrentOccupant and how you store the data type currently occupying the obj.
Computer too slow? Consider running a VM on your toaster.

User avatar
LuisR14
Posts: 1247
Joined: May 23rd, 2013, 3:52 pm
Location: USA
Contact:

Re: How dangerous is this class exactly?

Post by LuisR14 » June 7th, 2016, 6:24 pm

albinopapa wrote:After you pack your data efficiently, if the size of the struct/class is not a multiple of 4 or 8, then there will still be a gap between an array of these data structures.
yea that would be with the default packing, but that can be changed
albinopapa wrote:The only thing about structs/classes, is the order you put the members in. You list the largest data types first. This allows the data to be packed as tight as possible
not necessarily, it'll be packed to the largest even if not specified as 1st member, but it is good to do anyways
always available, always on, about ~10 years c/c++, java[script], win32/directx api, [x]html/css/php/some asp/sql experience. (all self taught)
Knows English, Spanish and Japanese.
[url=irc://irc.freenode.net/#pchili]irc://irc.freenode.net/#pchili[/url] [url=irc://luisr14.no-ip.org/#pchili]alt[/url] -- join up if ever want real-time help or to just chat :mrgreen: --

albinopapa
Posts: 4258
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: How dangerous is this class exactly?

Post by albinopapa » June 8th, 2016, 5:33 am

LuisR14 wrote:
albinopapa wrote:After you pack your data efficiently, if the size of the struct/class is not a multiple of 4 or 8, then there will still be a gap between an array of these data structures.
yea that would be with the default packing, but that can be changed
albinopapa wrote:The only thing about structs/classes, is the order you put the members in. You list the largest data types first. This allows the data to be packed as tight as possible
not necessarily, it'll be packed to the largest even if not specified as 1st member, but it is good to do anyways

That's weird. In all the tutorials I have run across, they say it matters what order you put your data in or the size and alignment would be off. I just ran some tests and as far as size, VS 2015 just rounds to the nearest 8 byte boundary by default.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
LuisR14
Posts: 1247
Joined: May 23rd, 2013, 3:52 pm
Location: USA
Contact:

Re: How dangerous is this class exactly?

Post by LuisR14 » June 8th, 2016, 7:30 am

albinopapa wrote:I just ran some tests and as far as size, VS 2015 just rounds to the nearest 8 byte boundary by default.
yea :p
always available, always on, about ~10 years c/c++, java[script], win32/directx api, [x]html/css/php/some asp/sql experience. (all self taught)
Knows English, Spanish and Japanese.
[url=irc://irc.freenode.net/#pchili]irc://irc.freenode.net/#pchili[/url] [url=irc://luisr14.no-ip.org/#pchili]alt[/url] -- join up if ever want real-time help or to just chat :mrgreen: --

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: How dangerous is this class exactly?

Post by cyboryxmen » June 8th, 2016, 8:03 am

albinopapa wrote:I guess what you need to ask yourself is, what's the goal?
The goal at the beginning is simple: have 1000 instances of one of 56 different objects be stored in memory without the ridiculousness of having 56 arrays. I am also trying to avoid a "one struct for all" solution since that has a lot of problems too especially since it would basically need to juggle the functionality of 56 different objects and you don't know which variable is used for which. Emulating how a union handles data and making them be able to share the same memory one at a time seems to be the most efficient solution to storing these objects in memory. Any other solution would either waste way too much memory or be really inefficient in comparison(50 times faster!).

A second goal that was created after I realise what a class like this can do in terms of type switching. I have grown weary of the limitations of polymorphism. Say that I have a base class called Shape. I want this class to calculate it's area and save it as any type I specify it to.

"Template functions cannot be virtual!"

Oh, I'll use double by default then. Now I have a nice class called SquareRenderer and I want it to try and render my shape if it is a square.

"You cannot reliably downcast with the tools available since dynamic_cast is so horribly implemented and supported."

I've been moving away from polymorphism because of this and have been seeking alternatives ever since. The Room class gives me a way to reveal it's stored type with optional type safety checks implemented which would make it a superior way to implement type switching if it wasn't for the fact that you need to type the switch() statement manually instead of having the compiler do it for you.
albinopapa wrote: If you are trying to optimize your program or worried about speed, then be specific in your code. Having a class that does general things is never going to be as fast as a class that does a specific task.
That would be insane. These classes are mostly disposable and would change every time I make a new project or try to make updates to existing ones. Having them line up in memory is already enough of a gain for me to strive for anyway(50 times faster!!!).
cameron wrote:I would be interested in seeing the rest of the implementation. I am curious about the implementation of EnumClass, GetCurrentOccupant and how you store the data type currently occupying the obj.
I tried to avoid having to show people my code too much since it uses a lot of template metaprogramming techniques that have a bad reputation for being hard to read. Most people are not familiar with them and even veterans of C++ avoid them because they hate their syntax(Google has practically banned them from their standard!)

TypeList.h

Code: Select all

#ifndef SHARED_TYPE_LIST_H_
#define SHARED_TYPE_LIST_H_
#include <utility>

namespace shared
{
	template<class FirstType, class SecondType, class...OtherTypes>
	//used to provide compile time information. Will never actually be compiled into final program.
	class TypeList
	{
	private:
		template<class Type>
		//an alias for convienient testing for void
		using IsVoid = std::is_same<Type, void>;

		template<class TestType, class TypeToCheckWith, class...OtherTypes>
		//check for duplicates on an individual type
		struct CheckTypeForDuplicates
		{
			enum
			{
				value = std::is_same<TestType, TypeToCheckWith>::value || CheckTypeForDuplicates<TestType, OtherTypes...>::value
			};
		};

		template<class TestType, class TypeToCheckWith>
		//recursion termination
		struct CheckTypeForDuplicates<TestType, TypeToCheckWith>
		{
			enum
			{
				value = std::is_same<TestType, TypeToCheckWith>::value
			};
		};

		template<class FirstType, class SecondType, class...OtherTypes>
		//check for duplicates on all given types
		struct CheckListForDuplicates
		{
			enum
			{
				value = CheckTypeForDuplicates<FirstType, SecondType, OtherTypes...>::value ||
				CheckListForDuplicates<SecondType, OtherTypes...>::value
			};

		};

		template<class SecondLastType, class LastType>
		//recursion termination
		struct CheckListForDuplicates<SecondLastType, LastType>
		{
			enum
			{
				value = CheckTypeForDuplicates<FirstType, SecondType>::value
			};
		};

		template<class FirstType, class...OtherTypes>
		//check for void types within a list of types
		struct CheckForVoid
		{
			enum
			{
				value = IsVoid<FirstType>::value || CheckForVoid<OtherTypes...>::value
			};
		};

		template<class LastType>
		//recursion termination
		struct CheckForVoid<LastType>
		{
			enum
			{
				value = IsVoid<LastType>::value
			};
		};

		template<class FirstType, class...Types>
		//represent an element in a list and used to create other elements in the list
		struct TypeListElement
		{
			using Type = FirstType;
			using Next = TypeListElement<Types...>;
		};

		template<class LastType>
		//recursion termination. Any other type after this will always be void.
		struct TypeListElement<LastType>
		{
			using Type = LastType;
			using Next = TypeListElement<void>;
		};

		template<class List, std::size_t index>
		//get element by index by counting down while going through the list. Will be void if we go out of scope.
		struct GetElementByIndex
		{
			//typename nessasary to declare member as type and not as value(because it's not like the program can just infer that it is or anything. Urgh...)
			using Element = typename GetElementByIndex<typename List::Next, index - std::size_t(1)>::Element;
		};
		
		template<class LastElement>
		//recursion termination.
		struct GetElementByIndex<LastElement, 1>
		{
			using Element = LastElement;
		};

		template<class List>
		//list will always have void as the first element
		struct GetElementByIndex<List, 0>
		{
			using Element = TypeListElement<void>;
		};

		template<class List, class CurrentType, class FindType, std::size_t current_index>
		//get the index of a type by finding a matching type in the list and counting the index.
		struct GetIndexOfElement
		{
			enum
			{
				index = GetIndexOfElement<typename List::Next, typename List::Type, FindType, current_index + std::size_t(1)>::index
			};
		};

		template<class List, class FoundType, std::size_t current_index>
		//when a matching type is found
		struct GetIndexOfElement<List, FoundType, FoundType, current_index>
		{
			enum
			{
				index = current_index
			};
		};

		template<class List, class TypeNotFound, std::size_t current_index>
		//when we reach the end of the list
		struct GetIndexOfElement<List, void, TypeNotFound, current_index>
		{
			enum
			{
				index = -1
			};
		};

		template<class List, class CurrentType, std::size_t current_index>
		//when void is searched for
		struct GetIndexOfElement<List, CurrentType, void, current_index>
		{
			enum
			{
				index = 0
			};
		};

		//an alias for convienient access to the list
		using List = TypeListElement<FirstType, SecondType, OtherTypes...>;

	public:
		//size = number of other types plus the first 2 types and void.
		enum
		{
			size = sizeof...(OtherTypes) + 2 + 1
		};

		template<std::size_t index>
		//alias for searching type by index
		using TypeAt = typename GetElementByIndex<List, index>::Element::Type;

		template<class Type>
		//alias for finding index of type
		using IndexOf = GetIndexOfElement<typename List::Next, typename List::Type, Type, 1>;

		//alias for checking for duplicates in the list
		using HasDuplicates = CheckListForDuplicates<FirstType, SecondType, OtherTypes...>;
		//alias for checking for void in the given types. List will always reserve the 0th member for void so there is no need for the user to give one.
		using HasVoid = CheckForVoid<FirstType, SecondType, OtherTypes...>;

	};
}
#endif
EnumClass.h

Code: Select all

#ifndef SHARED_ENUM_CLASS_H_
#define SHARED_ENUM_CLASS_H_
#include "TypeList.h"

namespace shared
{
	template<class Num, class FirstType, class SecondType, class...OtherTypes>
	class EnumClass
	{
	private:
		using List = TypeList<FirstType, SecondType, OtherTypes...>;
		static_assert(!List::HasDuplicates::value, "Cannot have duplicate Types!");
		static_assert(!List::HasVoid::value, "Cannot have void Types!");

	public:
		template<std::size_t index>
		using TypeAt = typename TypeList<FirstType, SecondType, OtherTypes...>::TypeAt<index>;

		template<class Type>
		using IndexOf = typename List::IndexOf<Type>;

	private:
		template<class Num, class FirstType, class SecondType, class...OtherTypes>
		//all versions of enum class is friends with every other version
		friend class EnumClass;
		Num enum_;

		template<class OtherList>
		//creates a table to convert an index from another list to our list
		struct ConversionTable
		{
		private:

			Num conversion[OtherList::size];

			//set the conversion table 
			template<class OtherList, std::size_t index, std::size_t TOTAL>
			struct SetTable
			{
				static void Set(Num*const conversion)
				{
					*conversion = IndexOf<typename OtherList::TypeAt<index>>::index;
					SetTable<OtherList, index + std::size_t(1), TOTAL>::Set(conversion + 1);
				}
			};

			//recursion termination
			template<class OtherList, std::size_t TOTAL>
			struct SetTable<OtherList, TOTAL, TOTAL>
			{
				static void Set(Num*const conversion)
				{
				}
			};

		public:
			ConversionTable()
			{
				SetTable<OtherList, 0, OtherList::size>::Set(conversion);
			}

			Num Convert(const Num& index) const
			{
				return conversion[index];
			}
		};

	public:
		EnumClass()
			:
			enum_(0)
		{
		}
		template<class FirstType, class SecondType, class...OtherTypes>
		EnumClass(const EnumClass<Num, FirstType, SecondType, OtherTypes...>& right_hand_side)
			:
			enum_(0)
		{
			//just use the table in the copy operator overload function to not waste memory.
			*this = right_hand_side;
		}

		template<class Type>
		Num Set()
		{
			static_assert(IndexOf<Type>::index != -1, "Error: Type does not exist within the TypeList!");
			enum_ = IndexOf<Type>::index;
			return enum_;
		}

		Num GetEnum() const
		{
			return enum_;
		}

		template<class FirstType, class SecondType, class...OtherTypes>
		EnumClass& operator=(const EnumClass<Num, FirstType, SecondType, OtherTypes...>& right_hand_side)
		{
			using OtherList = EnumClass<Num, FirstType, SecondType, OtherTypes...>::List;

			//one conversion table for every conversion made.
			static const ConversionTable<OtherList> conversion_table;

			enum_ = conversion_table.Convert(right_hand_side.enum_);
			return *this;
		}
	};
}
#endif
Room.h

Code: Select all

#ifndef SHARED_ROOM_H_
#define SHARED_ROOM_H_
#include <cstdint>
#include <exception>
#include "EnumClass.h"

namespace shared
{
	template<class Num, class FirstType, class SecondType, class...OtherTypes>
	class Room
	{
	public:
		using EnumClass = EnumClass<Num, FirstType, SecondType, OtherTypes...>;

		class Occupied : public std::exception
		{
		public:
			const char* what() const override
			{
				return "Room is already occupied(You should knock first next time!)";
			}
		};

		class WrongType : public std::exception
		{
		public:
			const char* what() const override
			{
				return "The type you are looking for is occupying another castle...err...room...";
			}
		};

	private:
		template<bool OverrideIfOccupied>
		struct DoOverrideIfOccupied
		{
			template<class Type>
			static void Override(Type& current_data, const Type& override_data, EnumClass& enum_class)
			{
				current_data = override_data;
				enum_class.Set<Type>();
			}
			template<class Type>
			//another for move semantics
			static void Override(Type& current_data, const Type&& override_data, EnumClass& enum_class)
			{
				current_data = override_data;
				enum_class.Set<Type>();
			}
		};

		template<>
		struct DoOverrideIfOccupied<false>
		{
			template<class Type>
			static void Override(Type& current_data, const Type& override_data, EnumClass& enum_class)
			{
				//if the room is occupied(not occupied by void)
				if (enum_class.GetEnum())
				{
					throw Occupied();
				}
				else
				{
					current_data = override_data;
					enum_class.Set<Type>();
				}
			}
			template<class Type>
			//another for move semantics
			static void Override(Type& current_data, const Type&& override_data, EnumClass& enum_class)
			{
				//if the room is occupied(not occupied by void)
				if (enum_class.GetEnum())
				{
					throw Occupied();
				}
				else
				{
					current_data = override_data;
					enum_class.Set<Type>();
				}
			}
		};

		template<class Type, bool CheckIfOccupying>
		struct DoCheckIfOccupying
		{
			static void Do(const EnumClass& enum_class)
			{
				//if the room is not being occupied by the given type
				if (enum_class.GetEnum() != EnumClass::IndexOf<Type>::index)
				{
					throw WrongType();
				}
			}
		};

		template<class Type>
		struct DoCheckIfOccupying<Type, false>
		{
			//will be optimised away
			static void Do(const EnumClass& enum_class)
			{
			}
		};

	public:
		Num GetCurrentOccupant() const
		{
			return enum_class_.GetEnum();
		}

		template<class Type, bool OverrideIfOccupied = false>
		void CheckIn(const Type& data)
		{
			DoOverrideIfOccupied<OverrideIfOccupied>::Override(GetData<Type>(), data, enum_class_);
		}

		template<class Type, bool OverrideIfOccupied = false>
		//another for move semantics
		void CheckIn(const Type&& data)
		{
			DoOverrideIfOccupied<OverrideIfOccupied>::Override(GetData<Type>(), data, enum_class_);
		}

		template<class Type, bool CheckIfOccupying = true>
		Type& Visit()
		{
			DoCheckIfOccupying<Type, CheckIfOccupying>::Do(enum_class_);

			return GetData<Type>();
		}

		template<class Type, bool CheckIfOccupying = true>
		const Type& Visit() const
		{
			DoCheckIfOccupying<Type, CheckIfOccupying>::Do(enum_class_);

			return GetData<Type>();
		}

	private:
		template<class FirstType, class SecondType, bool FirstTypeIsBigger>
		struct GetBiggestType
		{
			using Type = FirstType;
		};

		template<class FirstType, class SecondType>
		struct GetBiggestType<FirstType, SecondType, false>
		{
			using Type = SecondType;
		};

		template<class FirstType, class SecondType, class...OtherTypes>
		struct FindBiggestType
		{
			using Type = typename FindBiggestType<typename GetBiggestType<FirstType, SecondType, (sizeof(FirstType) > sizeof(SecondType))>::Type, OtherTypes...>::Type;
		};

		template<class SecondLastType, class LastType>
		struct FindBiggestType<SecondLastType, LastType>
		{
			using Type = typename GetBiggestType<SecondLastType, LastType, (sizeof(SecondLastType) > sizeof(LastType))>::Type;
		};

		enum
		{
			size = sizeof(FindBiggestType<FirstType, SecondType, OtherTypes...>::Type)
		};

		template<class Type>
		Type& GetData()
		{
			static_assert(EnumClass::IndexOf<Type>::index != -1, "Error: Type does not exist within the TypeList!");

			return *((Type*)data_);
		}

		template<class Type>
		const Type& GetData() const
		{
			static_assert(EnumClass::IndexOf<Type>::index != -1, "Error: Type does not exist within the TypeList!");

			return *((Type*)data_);
		}

		//disable copying once the room is created to force the program to use the safer CheckIn() function for copying.
		Room& operator=(const Room& room)
		{
			throw;
			return *this;
		}

		std::uint8_t data_[size];
		EnumClass enum_class_;
	};
}
#endif
I did moderate amounts of testing on these classes but it was never extensive. Try them out at your own risk. Also, they were coded in VS2013. Try not to use older versions of visual studio as they may not support the techniques used here.
-Zekilk
Last edited by cyboryxmen on June 8th, 2016, 10:17 am, edited 1 time in total.
Zekilk

User avatar
LuisR14
Posts: 1247
Joined: May 23rd, 2013, 3:52 pm
Location: USA
Contact:

Re: How dangerous is this class exactly?

Post by LuisR14 » June 8th, 2016, 8:50 am

cyboryxmen wrote:

Code: Select all

		//disable copying once the room is created to force the program to use the safer CheckIn() function for copying.
		Room& operator=(const Room& room)
		{
			throw;
			return *this;
		}
-Zekilk
why not just delete it?

Code: Select all

Room& operator=(const Room&) = delete;
always available, always on, about ~10 years c/c++, java[script], win32/directx api, [x]html/css/php/some asp/sql experience. (all self taught)
Knows English, Spanish and Japanese.
[url=irc://irc.freenode.net/#pchili]irc://irc.freenode.net/#pchili[/url] [url=irc://luisr14.no-ip.org/#pchili]alt[/url] -- join up if ever want real-time help or to just chat :mrgreen: --

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: How dangerous is this class exactly?

Post by cyboryxmen » June 8th, 2016, 9:57 am

LuisR14 wrote: why not just delete it?

Code: Select all

Room& operator=(const Room&) = delete;
I was unaware of that syntax. Thanks for the advice. I'm going to change all my code to use this instead. It really does seem that this class is the best solution to my problems and from what you guy's have posted, it may not be as dangerous as I fear. I'll just have to try to avoid using polymorphic classes with it.
-Zekilk
Zekilk

User avatar
chili
Site Admin
Posts: 3939
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: How dangerous is this class exactly?

Post by chili » June 8th, 2016, 1:19 pm

Remind me never to volunteer to debug any of your code cybord :D

BTW, I've noticed that VS2013 (haven't tried 2015) sometimes shits the bed when it comes to optimizing code that involves unions. Something to keep in mind.
Chili

Post Reply