Skip to content

Using raylib with Cpp

Eldinur edited this page Jul 31, 2024 · 5 revisions

This page will go over some of the common questions new users of raylib have when using C++.

How do I use raylib with C++?

raylib works with C++ in the exact same way it does with the C language. You can use raylib from C++ with no special modifications or build steps. Simply include raylib for your compiler and platform in the exact same way you do for C. raylib is fully compatible with both C and C++.

Do I have to use raylib-cpp to use raylib with C++?

No, raylib-cpp is not required to use raylib with C++. raylib-cpp is an optional wrapper that sits on top of the regular C raylib in order to provide object oriented access to raylib. raylib-cpp still calls the same C raylib in the end.

How can I fix C compound-literals related errors?

You can get the folllowing error when building raylib examples in C++:

A parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax

This type of structure initialization (Vector3){ 1.0f, 2.0f, 3.0f } is called a compound literal and is not supported by C++. Some C++ compilers are strict and will not allow it. This code can be converted to brace initialization in C++ by simply removing the parentheses around the type. Changing the code to Vector3{ 1.0f, 2.0f, 3.0f } will fix the error.

This change needs to be made for code that is pulled from the raylib C examples.

How can I draw my string?

DrawText() takes a const char *text, but I have a std::string in C++; std::string has a method named c_str(), this will return the const char *str stored in the string, use it as the argument for any C function that takes a const char *text. Example:

DrawText(my_string.c_str(),0,0,20,RED);

Shared GPU resources in constructors and destructors.

It is a common Object Oriented pattern to use Resource Acquisition Is Initialization (RAII). It may seem obvious to use this pattern with textures and models in raylib. This is possible to do, but the developer must be aware of the object lifetime, and when copies are made. For shared resources you need to follow the rule of 5 (https://en.cppreference.com/w/cpp/language/rule_of_three).

It is very common for new developer to make a class like this to automatically load an unload textures when things are created or go out of scope.

class MySprite
{
private:
	Texture2D m_texture = { 0 };
public:
	MySprite(Texture2D texture)
          :m_texture(texture);\
	{
	}

	~MySprite()
	{
		UnloadTexture(m_texture);
	}
};

The problem is when you use that class in code like this.

std::vector<MySprite> sprites;

MySprite aSprite(LoadTexture("Somefile.png"));
sprites.push_back(aSprite);

Push_back on the vector will make a copy of aSprite in the vector and then aSprite will go out of scope. The copy constructor for MySprite does not load a new texture, it just copies the ID values from the source texture. So then you have (for a short time) two objects that point to the same texture. When aSprite goes out of scope, it will call UnloadTexture and remove the texture ID from the GPU. So now you have a copy of the sprite in the container that points to an unloaded texture. This will not work for drawing.

If you want to use this pattern, you need to ensure that you don't make copies of things that contain shared resources. The simplest way to handle this is to remove the assignment and copy constructor operators and use std::move or emplace features to ensure that the container owns the data and manages the lifetime.

class MySprite
{
private:
	Texture2D m_texture = { 0 };
public:
	MySprite(Texture2D texture)
		: m_texture(texture)
	{
	}

	MySprite(const MySprite&) = delete;
	MySprite& operator = (const MySprite&) = delete;

	~MySprite()
	{
		UnloadTexture(m_texture);
	}
};

std::vector<MySprite> sprites;

sprites.emplace_back(LoadTexture("SomeFile.png"));

Scope and object lifetime are very important when dealing with this pattern.

Clone this wiki locally