Jump to content
  • Advertisement
noodleBowl

C++ General C++ class questions

Recommended Posts

I just have some general questions when it comes to C++ mainly focused on classes

1. When it comes to instantiating a class is there something like a static initializer? Or would it be better to have a static variable(s) and a corresponding flag to say whether or not the variables are ready to use?

2. Is it "bad" to throw exceptions in the constructor or should I use a 2 step initialization process? Example: I have TruckModel class and when I create a new instance I load in the mesh that this truck model uses. I throw an exception if the file cannot be found because I need the truck mesh in order to continue. This all happens within the TruckModel constructor

3. I am currently throwing some exceptions when critical errors happen and I guess exceptions do not work in the way I would expect. I sort of expect the program to come to screeching hault and fully stop execution, but it continues on if you just say to "continue" in the debugger. Simplified example:

#include <iostream>

int main()
{
	int count = 0;
	while (true)
	{
      		//Exception is thrown and there is no attempt to catch it
        	//Debugger says the exception occurs and complains, but I can carry on with my program like normal if I just ignore the complaints and keep stepping through until I come back to this point
		if (count == 10)
			throw std::exception("Something went wrong...");
      
		std::cout << "Count:" << count << std::endl;
		++count;
	}


	std::cout << "COMPLETE!" << std::endl;
}

4. Is it possible to hide a destructor from being directly called? I have classes that have a Release method to clean up various pointer resources used by the class instance. The destructor of the class does not call my Release method as that would free the resources prematurely in some cases. Example:

ResourceItem *ResourceCreator::createResourceItem(UINT size)
{
	ResourceItem resourceItem;
	system->CreateResourceItem(size, &resourceItem.dataPointer);
	resourceItems.push_back(resourceItem);

	return &resourceItems.back();
}
//resourceItem goes out of scope here. A call to the Release method in the destructor would free resources that should not be freed yet

5. When it comes to variables should I always be giving them a value in the constructor? I have noticed for pointer variables that they do not have NULL or nullptr as there value by default. So it has me wondering if all values are or could be garbage values at there start? Example:

class MyClass {

	public:
  		//Would expect this to be 0 by default. Not sure if I should set this to 0 in constructor because of potential default garbage value
		int count; 
		
  		//Would expect this to be NULL or nullptr, but have seen random garbage value as the default
  		OtherObject *otherObj;

}

 

Edited by noodleBowl

Share this post


Link to post
Share on other sites
Advertisement
34 minutes ago, noodleBowl said:

I just have some general questions when it comes to C++ mainly focused on classes

1. When it comes to instantiating a class is there something like a static initializer? Or would it be better to have a static variable(s) and a corresponding flag to say whether or not the variables are ready to use?

Static members are initialized once, automatically.

struct myclass {
	myclass();
	static int mystatic;
};

int myclass::mystatic = 42;

If you need to run arbitrary code in the constructor just once there are facilities for that as well; click.

#include <mutex>

myclass::myclass() {
	static std::once_flag onceflag;

	std::call_one(onceflag, []() {
		// code here will be executed just once
	});
}

 

34 minutes ago, noodleBowl said:

2. Is it "bad" to throw exceptions in the constructor or should I use a 2 step initialization process? Example: I have TruckModel class and when I create a new instance I load in the mesh that this truck model uses. I throw an exception if the file cannot be found because I need the truck mesh in order to continue. This all happens within the TruckModel constructor

Personally I would just do minimal amount of work in the constructor to put the object in a well-defined state. Non-trivial work that can fail goes into separate init functions. But there's nothing technically wrong with throwing from a constructor; the object just isn't constructed and doesn't come into existence in the first place.

34 minutes ago, noodleBowl said:

3. I am currently throwing some exceptions when critical errors happen and I guess exceptions do not work in the way I would expect. I sort of expect the program to come to screeching hault and fully stop execution, but it continues on if you just say to "continue" in the debugger. Simplified example:

Maybe the debugger just allows you to continue execution and "bypass" the exception. Run it without the debugger and see what happens instead.

34 minutes ago, noodleBowl said:

4. Is it possible to hide a destructor from being directly called? I have classes that have a Release method to clean up various pointer resources used by the class instance. The destructor of the class does not call my Release method as that would free the resources prematurely in some cases. Example:

That's the wrong solution to the problem. The core of the problem is that your class is not copyable, but you put a copy of it into the vector. Look up resource ownership, the rule of three/five/zero, and how to properly handle dynamic resources.

My guess is that the class contains a pointer to some resource (or equivalent; you mention a Release method so perhaps a COM-pointer), but you don't implement a proper copy constructor for your class. When you then make a copy, you have two objects holding a pointer to the same resource, and the first one to destruct will also release the resources.

Either implement a proper deep copy (rather than a shallow copy or pointer assignment) so two objects hold separate copies of the actual resource rather than copies of the pointer, or implement proper resource sharing (for example std::shared_ptr), depending on what you want to happen when you copy your objects.

34 minutes ago, noodleBowl said:

5. When it comes to variables should I always be giving them a value in the constructor? I have noticed for pointer variables that they do not have NULL or nullptr as there value by default. So it has me wondering if all values are or could be garbage values at there start? Example:

 

Primitive types are not initialized, you have to do that yourself.

class MyClass {
	public:
		int count = 0;
		OtherObject *otherObj = nullptr;
}

 

Share this post


Link to post
Share on other sites

Static variables are ok to be initialized in your class implementation file and there are technics to run data once either using STL as Brother Bob mentioned or some static local variable instances for something like read-only constants

typedef union Vector3
{
   public:
      static const Vector3 Zero()
      {
         static Vector3 zero = {{ 0, 0, 0 }}; //<- will be called once
         return zero;
      }
...
  
}vec3;

 

To my personal opinion, exceptions are overworked these days. Sure they are a tool to indicate very hard failure but most of the time a simple bool check/proper return value does the work. If your class is data related, give it operator bool overload and check if it got correctly instantiated. In case of your file example, this would lead to an inline file handle check to zero and then you have your proper state. I try to prevent exceptions whenever possible in my code.

You should design your class in a way that the destructor works as expected, calling it explicitly or not dosent matter here. One might leave local scope without calling your Release function and this is intended by the standard to call at least a classes destructor or default destructor. It is mostly wrong to expect calling a custom function for free up class data when leaving scope (what did not mean that there dosent might exist cases to do so). What you could do here is catching already freed data by doing a simple null-check for your data and call your custom function when the data still exists.

Storing data in a vector could then be done by either of these solutions to create an empty default instance to be passed into your vector and call custom initializer on its reference/pointer or provide a swap mechanism like STL containers do to exchange ownership of whatever is stored inside if you do not want your class to be copyable.

You should provide a basic initialization for your class members if possible at least to prevent nasty side effects (like working on an uninitialized but not null pointer). I use a constructor default if necessary

class MyClass
{
   public:
      inline MyClass() : myHandle(0)
      { }

   private:
      void* myHandle;
};

 

Share this post


Link to post
Share on other sites

1. Class static members are secretly just global variables of static storage duration.  They are explicitly initialized at their point of definition.

2.The use of exceptions (or not) in constructors is a deeply-held religious belief.  Ask this question and you will be proselytized here.  The right answer actually depends on what paradigm you're programming in.

3. Execution in a debugger is not normal execution. 

4. It is not possible to not fire the destructor on object destruction.  Your design is broken.  Look up the "rule of three" (or "rule of five') and reference counting, or else use the heap if the lifetime of your resource exceeds local scope.

5. All member variables are initialized in the constructor.  If you do not explicitly initialize them in your code, they will have their default constructor invoked.  The default constructor for built-in types like ints and pointers is normally "random" although some compilers in "debug" mode will set a known value.

Share this post


Link to post
Share on other sites
6 hours ago, noodleBowl said:

4. Is it possible to hide a destructor from being directly called? I have classes that have a Release method to clean up various pointer resources used by the class instance. The destructor of the class does not call my Release method as that would free the resources prematurely in some cases. Example:


ResourceItem *ResourceCreator::createResourceItem(UINT size)
{
	ResourceItem resourceItem;
	system->CreateResourceItem(size, &resourceItem.dataPointer);
	resourceItems.push_back(resourceItem);

	return &resourceItems.back();
}
//resourceItem goes out of scope here. A call to the Release method in the destructor

You could alleviate the problem by using move-semantics:

ResourceItem *ResourceCreator::createResourceItem(UINT size)
{
	ResourceItem resourceItem;
	system->CreateResourceItem(size, &resourceItem.dataPointer);
	resourceItems.push_back(std::move(resourceItem)); // instead of copying resourceItem, move its content into the container, leaving "resourceItem" in an uninitialized state

	return &resourceItems.back();
}
//resourceItem goes out of scope here. A call to the Release method in the destructor

The move-ctor would look something like this:

ResourceItem::ResourceItem(ResourceItem&& item) :
	dataPointer(item.dataPointer)
{
	item.dataPointer = nullptr;
}

Then when the dtor is called for resourceItem, it behaves exactly as if you deleted a default ResourceItem-instance, so you could pack Release in the dtor (if this is what you wanted).

On another note, even without move-semantics, why does this cause a problem in the first place? If you do reference-counting, copying the ResourceItem via copy-ctor should already by incrementing the ref-count by 1 (so on the push_back-line, you have 2 references, when ResourceItem goes out of scope it goes back to 1). In that case, move-semantics would be a tad faster OFC, but it should work eigther way if done right.

Share this post


Link to post
Share on other sites

For question 4, so I have several classes that have member variables that are COM-pointers. I also have some factory/manager type classes that create these objects and place them into a vector. That issue I was having is that when the local class (the one that is pushed back) goes out of scope the destructor is called, which it should be. But I also had code in there to clean up and free the COM-pointer. Unfortunately this caused the problem of resources being released when they should not

I think I actually have the rule of 5 implace for one of my classes (VertexShader), but I don't believe I have done it correctly as the COM-pointers (shader and inputLayout) that are released on the local copy cause the copy placed into the vector to have a dangling pointers (address is still there, but the object being pointed to does not really exist) and ultimately causes an access violation eventually. This is my current implementation:

//===== Header file for my VertexShader class
class VertexShader
{

public:
	VertexShader();
	~VertexShader();

	std::string id;
	VertexShader(std::string id);
	VertexShader(const VertexShader &other);
	VertexShader(VertexShader &&other);
	VertexShader &operator=(const VertexShader &other);

	//DirectX 11 COM-pointers that I want to free
	ID3D11VertexShader *shader;
	ID3D11InputLayout *inputLayout;

	void release();
};

//====== Implementation file for my VertexShader class
//Normal constructor
VertexShader::VertexShader()
{
	shader = nullptr;
	inputLayout = nullptr;
	std::cout << "Vertex Shader constructor called!" << std::endl;
}

//Normal constructor with id arg
VertexShader::VertexShader(std::string id)
{
	this->id = id;
	std::cout << "Vertex Shader constructor called. Id: " << this->id.c_str() << std::endl;
}

//Destructor
VertexShader::~VertexShader()
{
	std::cout << "Vertex Shader destructor called..." << std::endl;
	release(); //Having release in the destructor currentl gives me in issue :(
}

//Copy constructor
VertexShader::VertexShader(const VertexShader &other) {
	id = other.id + "-COPY-CON";
	shader = other.shader;
	inputLayout = other.inputLayout;
	std::cout << "Vertex Shader copy constructor called. Id: " << id << " Other Id: " << other.id << std::endl;
}

//Move constructor
VertexShader::VertexShader(VertexShader &&other)
{
	id = other.id + "-MOVE_CON";
	shader = other.shader;
	inputLayout = other.inputLayout;
	std::cout << "Vertex Shader move constructor called. Id: " << id << " Other Id: " << other.id << std::endl;
}

//Assignment operator
VertexShader &VertexShader::operator=(const VertexShader &other)
{
	if (&other != this) {
		id = other.id + "-ASSIGN-OPT";
		shader = other.shader;
		inputLayout = other.inputLayout;
	}

	std::cout << "Vertex Shader assignment operator called . Id: " << id << " Other Id: " << other.id << std::endl;
	return *this;
}

//Release method that frees the COM-pointers
void VertexShader::release()
{
	
	if (inputLayout != nullptr)
	{
		inputLayout->Release();
		inputLayout = nullptr;
	}

	if (shader != nullptr)
	{
		shader->Release();
		shader = nullptr;
	}

}

//Factory / Manager class method used to place a VertexShader into a vector
VertexShader *ShaderModule::createVertexShader(std::string id, LPCWSTR fileName, LPCSTR entryPoint, LPCSTR targetProfile, D3D11_INPUT_ELEMENT_DESC *inputElementsDescription, UINT inputElementDescriptionNumElements)
{
	ID3DBlob *shaderCode = compileShaderFromFile(fileName, entryPoint, targetProfile);

	VertexShader vertexShader(id);
	graphicsDevice->device->CreateVertexShader(shaderCode->GetBufferPointer(), shaderCode->GetBufferSize(), NULL, &vertexShader.shader);
	graphicsDevice->device->CreateInputLayout(inputElementsDescription, inputElementDescriptionNumElements, shaderCode->GetBufferPointer(), shaderCode->GetBufferSize(), &vertexShader.inputLayout);
	shaderCode->Release();

	vertexShaders.push_back(vertexShader);
	return &vertexShaders.back();
}
//vertexShader's destructor is called here, which in turn calls the release method. Freeing the COM-pointer object that later cause an access violation


//Example usage of my factory/manager
D3D11_INPUT_ELEMENT_DESC inputElementDescription[] = {
  { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
  { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
vShader = GraphicsModule::shaders.createVertexShader("VertexShader", L"default.shader", "VShader", "vs_4_0", inputElementDescription, 2);

 

Edited by noodleBowl

Share this post


Link to post
Share on other sites
2 hours ago, noodleBowl said:

I think I actually have the rule of 5 implace for one of my classes (VertexShader), but I don't believe I have done it correctly as the COM-pointers (shader and inputLayout) that are released on the local copy cause the copy placed into the vector to have a dangling pointers (address is still there, but the object being pointed to does not really exist) and ultimately causes an access violation eventually. This is my current implementation:

That's not correct copying. You will end up with two (or more) instances holding the same COM pointer, but the COM object's reference count is not increased to reflect the number of instances holding the COM object. Thus, when the first instance is destroyed, the COM object is released because, as far as it is concerned, the reference count is now zero and there are no more owners.

You need to manage the reference count when you make copies. I believe you do that with

shader->AddRef()

in your copy constructors. This will bump the reference count up when you make a copy of the pointer.

Or, you can use what C++ already offers.

#include <memory>
  
class VertexShader {
  public:
  	VertexShader(std::string id, ID3D11VertexShader *shader, ID3D11InputLayout *inputLayout);
  
  private:
	std::string id;
  	std::shared_ptr<ID3D11VertexShader> shader;
  	std::shared_ptr<ID3D11InputLayout> inputLayout;

}
  
VertexShader::VertexShader(std::string id, ID3D11VertexShader *shader, ID3D11InputLayout *inputLayout) :
  id(std::move(id))
{
  auto com_release_function = [](IUnknown *ptr) {
  	ptr->Release();
  }

  this->shader = std::shared_ptr<ID3D11VertexShader>(shader, com_release_function);
  this->inputLayout = std::shared_ptr<ID3D11InputLayout>(inputLayout, com_release_function);
}

VertexShader *ShaderModule::createVertexShader(...)
{
  VertexShader vertexShader(id);
  
  ID3D11VertexShader *shader;
  ID3D11InputLayout *inputLayout;
  
  graphicsDevice->device->CreateVertexShader(..., &shader);
  graphicsDevice->device->CreateInputLayout(..., &inputLayout);
  
  VertexShader vertexshader(id, shader, inputLayout);
  
  vertexShaders.push_back(vertexShader);
  return &vertexShaders.back();
}

Observe now that the class holds shared pointers that already implements proper sharing and destruction of a shared resource. There is no need to implement a destructor, copying, assignment, release function, or anything that will affect the lifetime of the COM pointers. The std::string manage itself, the two std::shared_ptrs also manage themselves, all automatically.

Share this post


Link to post
Share on other sites

Regarding exceptions from the constructor, in a good design the constructor should put the object in a reasonably complete and valid state; doing it without throwing exceptions is nicer, but if the constructor needs to do something that throws exceptions, handling exceptions (typically by throwing the towel at a fairly high level) is less inconvenient and less dangerous than handling invalid objects (everywhere and every time).

"Initialization" methods should be present for a specific reason: they are optional, they need to be called multiple times (e.g. to recycle old object in a pool), you don't know whether you want to call them (e.g. mutually exclusive alternatives like digesting two different types of 3D model), they cannot be consolidated into the constructor (e.g. the object is constructed in one thread and completely initialized in another thread), etc.

Edited by LorenzoGatti

Share this post


Link to post
Share on other sites
6 hours ago, LorenzoGatti said:

Regarding exceptions from the constructor

I feel like in some cases this unavoidable such as my example where I want to create a new mesh, but I can't load it's data from disk and well you can't have the mesh if you can't load in it's data. I guess I'm not really looking to catch and handle the exception. I'm really just looking to explode and say well we exploded cause of XYZ

6 hours ago, LorenzoGatti said:

Initialization" methods should be present for a specific reason

So I have a situation like the following:

class GameWindow {

public
   GameWindow(HINSTSNCE hInstance);
   ~GameWindow();

}

In order to create a GameWindow you must pass in a HINSTANCE. As this variable is required to actually setup the application window. But the compiler gets mad about not having the default no arg constructor. Which makes sense cause I believe if you define a constructor then the compiler does not automatically try to add one for you.

Now I thought I could just add one in and make it private (the default no arg constructor) and then this forces the use of the HINSTANCE version. But then you run into "cannot access" issue due to the constructor being private when you do something like:

class Game {

public:
   Game(HINSTANCE hInstance);
   ~Game();

private:
   GameWindow gameWindow; //compiler does not like this cause the default constructor is private

}

Which also makes sense I guess since GameWindow gameWindow is really just GameWindow gameWindow() right? It does not work like it would in Java or C# where GameWindow gameWindow is just a declaration and the value is null. In C++ it is literally an instance creation of the class

So in this case I would absolutely require an init method right? I can't Because I can't just change the line to use the GameWindow(HINSTANCE hInstance) constructor because that hInstance value has to come from somewhere and be set (not null or a junk value), which I don't think would happen in time in this case

Share this post


Link to post
Share on other sites
On 10/12/2017 at 1:40 PM, noodleBowl said:

I feel like in some cases this unavoidable such as my example where I want to create a new mesh, but I can't load it's data from disk and well you can't have the mesh if you can't load in it's data. I guess I'm not really looking to catch and handle the exception. I'm really just looking to explode and say well we exploded cause of XYZ

Personally, I would tackle your problem a bit differently.

I would either use a factory class or at the very least a static factory method that does the load / exception logic outside of the model's constructor.  Only once the file could be located and loaded does the factory class or method allocate a model and populate it.

On 10/12/2017 at 1:40 PM, noodleBowl said:

So in this case I would absolutely require an init method right?

No, the problem is how you're declaring the GameWindow variable.  I would have expected something more along the lines of the following instead:

class Game {
public:
  Game(HINSTANCE hInstance) : gameWindow( new GameWindow( hInstance ) ) {}
  ~Game() { delete gameWindow; }

private:
  GameWindow *gameWindow;
}

Or better yet, use a smart_ptr.

Edited by crancran

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By Andrew Parkes
      I am a talented 2D/3D artist with 3 years animation working experience and a Degree in Illustration and Animation. I have won a world-wide art competition hosted by SFX magazine and am looking to develop a survival game. I have some knowledge of C sharp and have notes for a survival based game with flexible storyline and PVP. Looking for developers to team up with. I can create models, animations and artwork and I have beginner knowledge of C sharp with Unity. The idea is Inventory menu based gameplay and is inspired by games like DAYZ.
      Here is some early sci-fi concept art to give you an idea of the work level. Hope to work with like minded people and create something special. email me andrewparkesanim@gmail.com.
      Developers who share the same passion please contact me, or if you have a similar project and want me to join your team email me. 
      Many thanks, Andrew.

    • By mike44
      Hi
      saw in dependency walker that my app still needs msvcp140d.dll even after disabling debug.
      What did I forget in the VS2017 release settings? After setting to multithreaded dll I get linker errors.
      Thanks
       
    • By 3dmodelerguy
      So I have been playing around with yaml-cpp as I want to use YAML for most of my game data files however I am running into some pretty big performance issues and not sure if it is something I am doing or the library itself.
      I created this code in order to test a moderately sized file:
      Player newPlayer = Player(); newPlayer.name = "new player"; newPlayer.maximumHealth = 1000; newPlayer.currentHealth = 1; Inventory newInventory; newInventory.maximumWeight = 10.9f; for (int z = 0; z < 10000; z++) { InventoryItem* newItem = new InventoryItem(); newItem->name = "Stone"; newItem->baseValue = 1; newItem->weight = 0.1f; newInventory.items.push_back(newItem); } YAML::Node newSavedGame; newSavedGame["player"] = newPlayer; newSavedGame["inventory"] = newInventory; This is where I ran into my first issue, memory consumption.
      Before I added this code, the memory usage of my game was about 22MB. After I added everything expect the YAML::Node stuff, it went up to 23MB, so far nothing unexpected. Then when I added the YAML::Node and added data to it, the memory went up to 108MB. I am not sure why when I add the class instance it only adds like 1MB of memory but then copying that data to a YAML:Node instance, it take another 85MB of memory.
      So putting that issue aside, I want want to test the performance of writing out the files. the initial attempt looked like this:
      void YamlUtility::saveAsFile(YAML::Node node, std::string filePath) { std::ofstream myfile; myfile.open(filePath); myfile << node << std::endl; myfile.close(); } To write out the file (that ends up to be about 570KB), it took about 8 seconds to do that. That seems really slow to me.
      After read the documentation a little more I decide to try a different route using the YAML::Emitter, the implemntation looked like this:
      static void buildYamlManually(std::ofstream& file, YAML::Node node) { YAML::Emitter out; out << YAML::BeginMap << YAML::Key << "player" << YAML::Value << YAML::BeginMap << YAML::Key << "name" << YAML::Value << node["player"]["name"].as<std::string>() << YAML::Key << "maximumHealth" << YAML::Value << node["player"]["maximumHealth"].as<int>() << YAML::Key << "currentHealth" << YAML::Value << node["player"]["currentHealth"].as<int>() << YAML::EndMap; out << YAML::BeginSeq; std::vector<InventoryItem*> items = node["inventory"]["items"].as<std::vector<InventoryItem*>>(); for (InventoryItem* const value : items) { out << YAML::BeginMap << YAML::Key << "name" << YAML::Value << value->name << YAML::Key << "baseValue" << YAML::Value << value->baseValue << YAML::Key << "weight" << YAML::Value << value->weight << YAML::EndMap; } out << YAML::EndSeq; out << YAML::EndMap; file << out.c_str() << std::endl; } While this did seem to improve the speed, it was still take about 7 seconds instead of 8 seconds.
      Since it has been a while since I used C++ and was not sure if this was normal, I decided to for testing just write a simple method to manually generate the YAMLin this use case, that looked something like this:
      static void buildYamlManually(std::ofstream& file, SavedGame savedGame) { file << "player: \n" << " name: " << savedGame.player.name << "\n maximumHealth: " << savedGame.player.maximumHealth << "\n currentHealth: " << savedGame.player.currentHealth << "\ninventory:" << "\n maximumWeight: " << savedGame.inventory.maximumWeight << "\n items:"; for (InventoryItem* const value : savedGame.inventory.items) { file << "\n - name: " << value->name << "\n baseValue: " << value->baseValue << "\n weight: " << value->weight; } } This wrote the same file and it took about 0.15 seconds which seemed a lot more to what I was expecting.
      While I would expect some overhead in using yaml-cpp to manage and write out YAML files, it consuming 70X+ the amount of memory and it being 40X+ slower in writing files seems really bad.
      I am not sure if I am doing something wrong with how I am using yaml-cpp that would be causing this issue or maybe it was never design to handle large files but was just wondering if anyone has any insight on what might be happening here (or an alternative to dealing with YAMLin C++)?
    • By 3dmodelerguy
      So I am trying to using Yaml as my game data files (mainly because it support comments, is a bit easier to read than JSON, and I am going to be working in these files a lot) with C++ and yaml-cpp (https://github.com/jbeder/yaml-cpp) seems like the most popular library for dealing with it however I am running into an issue when using pointers.
      Here is my code:
      struct InventoryItem { std::string name; int baseValue; float weight; }; struct Inventory { float maximumWeight; std::vector<InventoryItem*> items; }; namespace YAML { template <> struct convert<InventoryItem*> { static Node encode(const InventoryItem* inventoryItem) { Node node; node["name"] = inventoryItem->name; node["baseValue"] = inventoryItem->baseValue; node["weight"] = inventoryItem->weight; return node; } static bool decode(const Node& node, InventoryItem* inventoryItem) { // @todo validation inventoryItem->name = node["name"].as<std::string>(); inventoryItem->baseValue = node["baseValue"].as<int>(); inventoryItem->weight = node["weight"].as<float>(); return true; } }; template <> struct convert<Inventory> { static Node encode(const Inventory& inventory) { Node node; node["maximumWeight"] = inventory.maximumWeight; node["items"] = inventory.items; return node; } static bool decode(const Node& node, Inventory& inventory) { // @todo validation inventory.maximumWeight = node["maximumWeight"].as<float>(); inventory.items = node["items"].as<std::vector<InventoryItem*>>(); return true; } }; } if I just did `std::vector<InventoryItem> items` and had the encode / decode use `InventoryItem& inventoryItem` everything works fine however when I use the code above that has it as a pointer, I get the following error from code that is part of the yaml-cpp library:
      impl.h(123): error C4700: uninitialized local variable 't' used The code with the error is:
      template <typename T> struct as_if<T, void> { explicit as_if(const Node& node_) : node(node_) {} const Node& node; T operator()() const { if (!node.m_pNode) throw TypedBadConversion<T>(node.Mark()); T t; if (convert<T>::decode(node, t)) // NOTE: THIS IS THE LINE THE COMPILER ERROR IS REFERENCING return t; throw TypedBadConversion<T>(node.Mark()); } }; With my relative lack of experience in C++ and not being able to find any documentation for yaml-cpp using pointers, I am not exactly sure what is wrong with my code.
      Anyone have any ideas what I need to change with my code? 
    • By Gnollrunner
      I already asked this question on stack overflow, and they got pissed at me, down-voted me and so forth, LOL .... so I'm pretty sure the answer is NO, but I'll try again here anyway just in case..... Is there any way to get the size of a polymorphic object at run-time? I know you can create a virtual function that returns size and overload it for each child class, but I'm trying to avoid that since (a) it takes a virtual function call and I want it to be fast and (b) it's a pain to have to include the size function for every subclass. I figure since each object has a v-table their should be some way since the information is there, but perhaps there is no portable way to do it.
    • By MarcusAseth
      This is the code I have:
       //Create Window     DWORD windowStyle = WS_VISIBLE;     DWORD windowExStyle = WS_EX_OVERLAPPEDWINDOW;     SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);     RECT client{ 0, 0, 100, 40 };     UINT dpi = GetDpiForSystem();     AdjustWindowRectExForDpi(&client, windowStyle, false, windowExStyle, dpi);     UINT adjustedWidth = client.right - client.left;     UINT adjustedHeight = client.bottom - client.top;     m_hwnd = CreateWindowEx(windowExStyle,                             className.c_str(),                             windowName.c_str(),                             windowStyle,                             CW_USEDEFAULT,                             CW_USEDEFAULT,                             adjustedWidth,                             adjustedHeight,                             nullptr,                             nullptr,                             m_hInstance,                             m_emu     ); The generated window has a client area of 1 pixel in height, even though I'm asking for 40. so I'm always getting 39 pixel less than what I need...can someone help me with this? x_x
    • By SeraphLance
      I've spent quite a while (and probably far longer than I actually should) trying to design an allocator system.  I've bounced ideas around to various people in the past, but never really gotten something satisfactory.
      Basically, the requirements I'm trying to target are:
        Composability -- allocators that seamlessly allocate from memory allocated by other allocators.  This helps me to do things like, for example, write an allocator that pads allocations from its parent allocator with bit patterns to detect heap corruption.  It also allows me to easily create spillovers, or optionally assert on overflow with specialized fallbacks.   Handling the fact that some allocators have different interfaces than others in an elegant way.  For example, a regular allocator might have Allocate/Deallocate, but a linear allocator can't do itemized deallocation (but can deallocate everything at once).   I want to be able to tell how much I've allocated, and how much of that is actually being used.  I also want to be able to bucket that on subsystem, but as far as I can tell, that doesn't really impact the design outside of adding a new parameter to allocate calls. Note:  I'm avoiding implementation of allocation buckets and alignment from this, since it's largely orthogonal to what I'm asking and can be done with any of the designs.
       
      To meet those three requirements, I've come up with the following solutions, all of which have significant drawbacks.
      Static Policy-Based Allocators
      I originally built this off of this talk.
      Examples;
      struct AllocBlock { std::byte* ptr; size_t size; }; class Mallocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size); void Deallocate(AllocBlock blk); }; template <typename BackingAllocator, size_t allocSize> class LinearAllocator : BackingAllocator { AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator() : baseMemory(BackingAllocator::Allocate(allocSize)) { /* stuff */ } AllocBlock Allocate(size_t size); }; template <typename BackingAllocator, size_t allocSize> class PoolAllocator : BackingAllocator { AllocBlock baseMemory; char* currentHead; public: PoolAllocator() : baseMemory(BackingAllocator::Allocate(allocSize)) { /* stuff */ } void* Allocate(); // note the different signature. void Deallocate(void*); }; // ex: auto allocator = PoolAllocator<Mallocator, size>; Advantages:
      SFINAE gives me a pseudo-duck-typing thing.  I don't need any kind of common interfaces, and I'll get a compile-time error if I try to do something like create a LinearAllocator backed by a PoolAllocator. It's composable. Disadvantages:
      Composability is type composability, meaning every allocator I create has an independent chain of compositions.  This makes tracking memory usage pretty hard, and presumably can cause me external fragmentation issues.  I might able to get around this with some kind of singleton kung-fu, but I'm unsure as I don't really have any experience with them. Owing to the above, all of my customization points have to be template parameters because the concept relies on empty constructors.  This isn't a huge issue, but it makes defining allocators cumbersome. Dynamic Allocator Dependency
      This is probably just the strategy pattern, but then again everything involving polymorphic type composition looks like the strategy pattern to me. 😃
      Examples:
      struct AllocBlock { std::byte* ptr; size_t size; }; class Allocator { virtual AllocBlock Allocate(size_t) = 0; virtual void Deallocate(AllocBlock) = 0; }; class Mallocator : Allocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size); void Deallocate(AllocBlock blk); }; class LinearAllocator { Allocator* backingAllocator; AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator(Allocator* backingAllocator, size_t allocSize) : backingAllocator(backingAllocator) { baseMemory = backingAllocator->Allocate(allocSize); /* stuff */ } AllocBlock Allocate(size_t size); }; class PoolAllocator { Allocator* backingAllocator; AllocBlock baseMemory; char* currentHead; public: PoolAllocator(Allocator* backingAllocator, size_t allocSize) : backingAllocator(backingAllocator) { baseMemory = backingAllocator->Allocate(allocSize); /* stuff */ } void* Allocate(); // note the different signature. void Deallocate(void*); }; // ex: auto allocator = PoolAllocator(someGlobalMallocator, size); There's an obvious problem with the above:  Namely that PoolAllocator and LinearAllocator don't inherit from the generic Allocator interface.  They can't, because their interfaces provide different semantics.  There's to ways I can solve this:
        Inherit from Allocator anyway and assert on unsupported operations (delegates composition failure to runtime errors, which I'd rather avoid).   As above:  Don't inherit and just deal with the fact that some composability is lost (not ideal, because it means you can't do things like back a pool allocator with a linear allocator) As for the overall structure, I think it looks something like this:
      Advantages:
      Memory usage tracking is easy, since I can use the top-level mallocator(s) to keep track of total memory allocated, and all of the leaf allocators to track of used memory.  How to do that in particular is outside the scope of what I'm asking about, but I've got some ideas. I still have composability Disadvantages:
      The interface issues above.  There's no duck-typing-like mechanism to help here, and I'm strongly of the opinion that programmer errors in construction like that should fail at compile-time, not runtime. Composition on Allocated Memory instead of Allocators
      This is probably going to be somewhat buggy and poorly thought, since it's just an idea rather than something I've actually tried.
      Examples:
      struct AllocBlock { void* ptr; size_t size; std::function<void()> dealloc; } class Mallocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size) { void* ptr = malloc(size); return {ptr, size, [ptr](){ free(ptr); }}; } }; class LinearAllocator { AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator(AllocBlock baseMemory) : baseMemory(baseMemory) {end = ptr = baseMemory.ptr;} AllocBlock Allocate(size_t); }; class PoolAllocator { AllocBlock baseMemory; char* head; public: PoolAllocator(AllocBlock baseMemory) : baseMemory(baseMemory) { /* stuff */ } void* Allocate(); }; // ex: auto allocator = PoolAllocator(someGlobalMallocator.Allocate(size)); I don't really like this design at first blush, but I haven't really tried it.

      Advantages:
      "Composable", since we've delegated most of what composition entails into the memory block rather than the allocator. Tracking memory is a bit more complex, but I *think* it's still doable. Disadvantages:
      Makes the interface more complex, since we have to allocate first and then pass that block into our "child" allocator. Can't do specialized deallocation (i.e. stack deallocation) since the memory blocks don't know anything about their parent allocation pool.  I might be able to get around this though.  
      I've done a lot of research against all of the source-available engines I can find, and it seems like most of them either have very small allocator systems or simply don't try to make them composable at all (CryEngine does this, for example).  That said, it seems like something that should have a lot of good examples, but I can't find a whole lot.  Does anyone have any good feedback/suggestions on this, or is composability in general just a pipe dream?
    • By RobMaddison
      Hi
      I’ve been working on a game engine for years and I’ve recently come back to it after a couple of years break.  Because my engine uses DirectX9.0c I thought maybe it would be a good idea to upgrade it to DX11. I then installed Windows 10 and starting tinkering around with the engine trying to refamiliarise myself with all the code.
      It all seems to work ok in the new OS but there’s something I’ve noticed that has caused a massive slowdown in frame rate. My engine has a relatively sophisticated terrain system which includes the ability to paint roads onto it, ala CryEngine. The roads are spline curves and built up with polygons matching the terrain surface. It used to work perfectly but I’ve noticed that when I’m dynamically adding the roads, which involves moving the spline curve control points around the surface of the terrain, the frame rate comes to a grinding halt.
      There’s some relatively complex processing going on each time the mouse moves - the road either side of the control point(s) being moved, is reconstructed in real time so you can position and bend the road precisely. On my previous OS, which was Win2k Pro, this worked really smoothly and in release mode there was barely any slow down in frame rate, but now it’s unusable. As part of the road reconstruction, I lock the vertex and index buffers and refill them with the new values so my question is, on windows 10 using DX9, is anyone aware of any locking issues? I’m aware that there can be contention when locking buffers dynamically but I’m locking with LOCK_DISCARD and this has never been an issue before.
      Any help would be greatly appreciated.
    • By LukeCassa005
      I'm writing a small 3D Vulkan game engine using C++. I'm working in a team, and the other members really don't know almost anything about C++. About three years ago i found this new programming language called D wich seems very interesting, as it's very similar to C++. My idea was to implement core systems like rendering, math, serialization and so on using C++ and then wrapping all with a D framework, easier to use and less complicated. Is it worth it or I should stick only to C++ ? Does it have less performance compared to a pure c++ application ?
    • By MarcusAseth
      Hi guys, I'm trying to learn this stuff but running into some problems 😕
      I've compiled my .hlsl into a header file which contains the global variable with the precompiled shader data:
      //... // Approximately 83 instruction slots used #endif const BYTE g_vs[] = { 68, 88, 66, 67, 143, 82, 13, 236, 152, 133, 219, 113, 173, 135, 18, 87, 122, 208, 124, 76, 1, 0, 0, 0, 16, 76, 0, 0, 6, 0, //.... And now following the "Compiling at build time to header files" example at this msdn link , I've included the header files in my main.cpp and I'm trying to create the vertex shader like this:
      hr = g_d3dDevice->CreateVertexShader(g_vs, sizeof(g_vs), nullptr, &g_d3dVertexShader); if (FAILED(hr)) { return -1; } and this is failing, entering the if and returing -1.
      Can someone point out what I'm doing wrong? 😕 
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631354
    • Total Posts
      2999498
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!