Entity Creation

About

To utilize features of the MAXON API it is typically needed to allocate an object that provides access to data and functions. These objects can either be simple C++ structures and classes or reference classes representing implementations of interfaces.

Object Creation

Simple objects can be allocated using the following memory management tools of the MAXON API. If it is necessary to allocate objects directly, these functions should always be used instead of the standard C++ allocators.

  • NewObj(): Creates an object of the given type with the given parameters. For handling the returned error see Error Handling.
  • DeleteObj(): Deletes the given object.
Note
If possible, one should always use reference counting. See References.

For allocation of low-level memory see Memory Allocation.

// This example shows a C++ custom class.
//----------------------------------------------------------------------------------------
// A simple class storing an integer value.
//----------------------------------------------------------------------------------------
class ExampleClass
{
public:
//----------------------------------------------------------------------------------------
// Constructor.
// @param[in] number The number to store.
//----------------------------------------------------------------------------------------
MAXON_IMPLICIT ExampleClass(maxon::Int number)
{
_number = number;
}
//----------------------------------------------------------------------------------------
// Constructor. The internal number is set to 0.
//----------------------------------------------------------------------------------------
MAXON_IMPLICIT ExampleClass()
{
_number = 0;
}
//----------------------------------------------------------------------------------------
// Returns the stored number.
// @return The number.
//----------------------------------------------------------------------------------------
maxon::Int GetNumber()
{
return _number;
}
//----------------------------------------------------------------------------------------
// Sets the stored number.
// @param[in] number The number to store.
//----------------------------------------------------------------------------------------
void SetNumber(maxon::Int number)
{
_number = number;
}
private:
maxon::Int _number;
};
// This example creates a new instance of the example class using NewObj().
// create the new object
ExampleClass* exampleObject = NewObj(ExampleClass, 100) iferr_return;
// use the object
const maxon::Int number = exampleObject->GetNumber();
DiagnosticOutput("Number: @", number);
// delete the object
DeleteObj(exampleObject);

Most complex classes of the MAXON API provide a (static) "Create()" function that can be used to create new instances. It is recommended to add such a "Create()" function also to a custom class if it must be initialized after creation.

// This example shows a simple class that provides a static Create() function.
// This Create() function allocates a new instances and initializes it. Only if
// the creation and initialization were successful, a new object is returned.
//----------------------------------------------------------------------------------------
// Class to store an array of ascending integer numbers.
//----------------------------------------------------------------------------------------
class AscendingNumbers
{
private:
//----------------------------------------------------------------------------------------
// Inits the array with elements defined by the given range.
// @param[in] start The minimum value.
// @param[in] end The maximum value.
// @return maxon::OK on success.
//----------------------------------------------------------------------------------------
{
// clear array
_numbers.Flush();
if (end < start)
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
// fill array with ascending integer values
for (maxon::Int i = start; i <= end; i++)
{
_numbers.Append(i) iferr_return;
}
return maxon::OK;
}
private:
public:
//----------------------------------------------------------------------------------------
// Static function to create a new AscendingNumbers instance.
// @param[in] start The minimum value.
// @param[in] end The maximum value.
// @return The new AscendingNumbers instance. The caller owns the object.
//----------------------------------------------------------------------------------------
{
// create object
AscendingNumbers* const numbers = NewObj(AscendingNumbers) iferr_return;
// take ownership to ensure memory clean-up in case of an error
using AscendingNumbersRef = maxon::UniqueRef<AscendingNumbers>;
AscendingNumbersRef ref(numbers);
// init array
numbers->Init(start, end) iferr_return;
// release and return
return ref.Disconnect();
}
//----------------------------------------------------------------------------------------
// Returns the number of stored elements.
// @return The number of stored elements.
//----------------------------------------------------------------------------------------
{
return _numbers.GetCount();
}
//----------------------------------------------------------------------------------------
// Returns the number at the given index.
// @param[in] index The index position of the number to access.
// @return The number at the given index.
//----------------------------------------------------------------------------------------
{
// range check
const maxon::Bool undershoot = index < 0;
const maxon::Bool overshoot = index >= _numbers.GetCount();
if (undershoot || overshoot)
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
return _numbers[index];
}
//----------------------------------------------------------------------------------------
// Copies the data of the given AscendingNumbers object. Will delete all previously stored data.
// @param[in] src Source AscendingNumbers-object to copy from.
// @return maxon::OK on success.
//----------------------------------------------------------------------------------------
maxon::Result<void> CopyFrom(const AscendingNumbers& src)
{
_numbers.CopyFrom(src._numbers) iferr_return;
return maxon::OK;
}
};
// This example shows how to use the static Create() function to allocate a new instance.
// create new instance
AscendingNumbers* const numbers = AscendingNumbers::Create(10, 20) iferr_return;
// defining a StrongRef alias to store the new instance
using AscendingNumbersRef = maxon::StrongRef<AscendingNumbers>;
// reference takes ownership to ensure memory clean-up
AscendingNumbersRef ref(numbers);
// use object
const maxon::Int count = numbers->GetCount();
for (maxon::Int i = 0; i < count; ++i)
{
const maxon::Int number = numbers->GetNumber(i) iferr_return;
DiagnosticOutput("Number @", number);
}

Interface References

A reference object represents an implementation of a given interface. Such a reference object can be created in various ways. For details see Interface Basics and Using Interfaces.

Note
References to interfaces with only one implementation can often be allocated on the stack e.g. maxon::String.

This example shows how a reference class instance is created using the maxon::Id of the specific implementation:

// This example creates an instance of an interface
// and uses the created instance.
// define the ID of the component to use
const maxon::Id id { "net.maxonexample.class.somesimpleclass" };
// get component class of the given ID from the global maxon::Classes registry
const maxon::Class<SimpleClassRef>& componentClass = maxon::Classes::Get<SimpleClassRef>(id);
// create reference
const SimpleClassRef simpleClass = componentClass.Create() iferr_return;
// use reference
simpleClass.SetNumber(123);
const maxon::Int number = simpleClass.GetNumber();
DiagnosticOutput("Number: @", number);

This example shows how to obtain a reference class from an implementation that is presented as a published object. See Published Objects Usage.

// This example creates a reference class from a component
// registered at the given declaration.
// create reference
// The "SomeSimpleClass" published object is declared in a header file.
// The obtained component is used to create a new instance using Create().
const SimpleClassRef simpleClass = SomeSimpleClass().Create() iferr_return;
// use reference
simpleClass.SetNumber(456);
const maxon::Int number = simpleClass.GetNumber();
DiagnosticOutput("Number: @", number);

Interface implementations can also be registered at registries. From these registries the reference class is obtained using the specific maxon::Id of the registered implementation. See Registry Usage.

// This example creates a reference object from the registry with the given ID.
// get the class with the given Id from the registry "ColorClasses"
const maxon::Id redID { "net.maxonexample.class.colors.red" };
const maxon::Class<ColorRef>* const componentClass = ColorClasses::Find(redID);
if (componentClass == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not get color."_s);
// create reference object
const ColorRef color = componentClass->Create() iferr_return;
// use reference object
const maxon::String colorName = color.GetName();
const maxon::Color32 colorRGB = color.GetRGB();
DiagnosticOutput("Color Name: @", colorName);
DiagnosticOutput("Color RGB: @", colorRGB);

Interfaces support inheritance. This means a given reference object of a base class can be cast into the reference class of a derived interface. If the cast is not possible a nullptr is returned.

  • maxon::Cast(): Casts the object into the given interface type.
  • maxon::AssertCast(): Casts the object into the given interface type. Checks only, if the object is really an instance of the interface in debug mode.
// This example accesses an error and casts it into a maxon::ErrnoError to get the stored error code.
// perform task
const maxon::Result<void> res = PerformTaskCheckError();
// check for failure
if (res == maxon::FAILED)
{
const maxon::Error error = res.GetError();
if (error.IsInstanceOf<maxon::ErrnoError>())
{
// cast into ErrnoError and access error code
const maxon::ErrnoError errnoError = maxon::Cast<maxon::ErrnoError>(error);
const maxon::Int errorCode = errnoError.GetErrorCode();
DiagnosticOutput("Error Code: @", errorCode);
}
}

Further Reading