Why is the copy assignment operator created from the `GDCLASS` macro defined with an empty implementation?

Godot Version

4.4.1

Question

I was implementing a class that was inheriting from godot::Object, so I used the GDCLASS macro at the top of my class. However, I got a compiler error because copy assignment operator= was already defined. It is defined in the GDCLASS macro.

	void operator=(const m_class & /*p_rval*/) {}

Since it is defined there with an empty implementation, how can I define my own custom copy assignment operator? Also, the copy assignment operator in the macro returns void, and I was thinking that normally this operator should return a reference to the instance that got assigned.

What language are you doing this in?

I am using C++.

I’ve never used GDExtension. @gertkeno might have an idea for you.

I’d guess it’s to force more explicit initialization with Godot’s memory management memnew. You don’t want to copy a FFI object and end up leaving the foreign functions behind. More context might help, what are you trying to do with a copy constructor? How do you think it may help your workflow?

1 Like

I don’t remember exactly why I wanted to define operator=. Also, sorry, I don’t quite understand what you mean by “leaving the foreign functions behind”.

Originally, when I was trying to write a class, I was initializing a TileMapLayer node in the class by using memnew and attempting to put it in a std::unique_ptr with a custom deleter that uses memdelete. Now, I have learned to allocate a TileMapLayer node that I then add to the scene with this->add_child. Then, I think that the Godot engine owns the memory of the TileMapLayer node, and my class just keeps a pointer to it.

So, I don’t believe that I need to make a custom copy assignment operator anymore.

However, I do still feel like it is weird that the copy assignment operator provided by the GDCLASS macro has an empty implementation. I think it could lead to unintuitive behavior.

For example:

struct Noun {
	int value{};
	constexpr void operator=(Noun const &that) {
		/* (empty implementation like how `GDCLASS` defines it) */
	}
};

Noun constexpr noun1{5};
static_assert(noun1.value == 5);

Noun constexpr noun2 = []() {
	Noun noun{-1};
	/*
		It looks like `noun2` will get the value of 5,
		but `operator=` has an empty implementation.
	*/
	noun = noun1;
	return noun;
}();
// It's unintuitive that `noun2` didn't get the value of 5.
static_assert(noun2.value == -1);

If they wanted to prevent the usage of the copy assignment operator, I wonder if it would have been suitable to mark it as deleted:

struct Noun {
	int value{};
	constexpr void operator=(Noun const &that) = delete;
};

Noun constexpr noun1{5};
static_assert(noun1.value == 5);

Noun constexpr noun2 = []() {
	Noun noun{-1};
	noun = noun1; // Now, this does not compile.
	return noun;
}();
1 Like

it was defined as private, preventing one from calling the copy constructor i assume?
though yeah wouldnt the delete apporach be whats the norm these days?

though it doesnt stop you from calling it in the class itself which is silly lol.