0

I am trying to create a wanderer attribute of my class Wanderer in my environmentGame.

I declare it in the environmentGame hpp file :

Wanderer gaspard;

And then I initialise it in my GameEnvironment cpp file :

void GameEnvironment::initWanderer()
{
    this->gaspard = Wanderer(this->_magic, this->_sphere, this->_textureProgram);
}

I have this error : in gameEnvironment

use of deleted function ‘Wanderer& Wanderer::operator=(Wanderer&&)’GCC Wanderer.hpp(12, 7): ‘Wanderer& Wanderer::operator=(Wanderer&&)’ is implicitly deleted >because the default definition would be ill-formed:

in Wanderer

use of deleted function ‘Object& Object::operator=(Object&&)’GCC Object.hpp(13, 7): ‘Object& Object::operator=(Object&&)’ is implicitly deleted because the >default definition would be ill-formed:

in Object

non-static reference member ‘ObjectProgram& Object::_program’, can’t use default >assignment operatorGCC

If I declare std::vector<Wanderer> gaspard; and then I push_back a wanderer in my init function this->gaspard = Wanderer(this->_magic, this->_sphere, this->_textureProgram); It works. But I need only one wanderer so it's not a very good option to have a vector.

Here is the class Wanderer :

class Wanderer : public Object 
{ 
    private :  

    public : 
        Wanderer();
        Wanderer(std::vector<FacesGroup> model, std::vector<FacesGroup> lodModel, ObjectProgram& program);

        // void init(std::vector<FacesGroup> facesGroup, ObjectProgram& program);
        void update_position(const TrackballCamera& viewMatrix); 

}; 

Wanderer inherits from

class Object 
{

    private : 

    protected : 
        glm::vec3 _position ; 
        float _scale  = 0.1 ; 
        std::vector<std::vector<FacesGroup>> _models; 
        ObjectProgram& _program; 
        // ShadowMapProgram& _shadowMapProgram;
        float _angle = 0.f;
        int _lod = 0; 


    public : 
        Object(std::vector<FacesGroup> model, std::vector<FacesGroup> lodModel, ObjectProgram& program);
        Object();
        // ~Object();
        
        void checkLOD();
        void deleteVAO_VBO();

        glm::vec3 getPosition() const; 
        void draw(const glm::mat4 ViewMatrix, const int windowWidth, const int windowHeight, std::map<std::string, Material>& materialMap, glm::vec3 wandererPos, int color); 

    }; 

And finaly ObjectProgram :

#pragma once

#include "p6/p6.h"

struct ObjectProgram
{
    p6::Shader _Program;

    GLint      uMVPMatrix;
    GLint      uMVMatrix;
    GLint      uNormalMatrix;

    GLint uTexture;

    GLint uKd;
    GLint uKs;
    GLint uShininess;

    GLint uLightPos_vs;
    GLint uLightDir_vs;
    GLint uLightCharacter_vs;
    GLint uLightIntensity;

    ObjectProgram() : _Program(p6::load_shader("shaders/3D.vs.glsl", "shaders/texture.fs.glsl"))
    {
        uMVPMatrix    = glGetUniformLocation(_Program.id(), "uMVPMatrix");
        uMVMatrix     = glGetUniformLocation(_Program.id(), "uMVMatrix");
        uNormalMatrix = glGetUniformLocation(_Program.id(), "uNormalMatrix");
        
        uTexture = glGetUniformLocation(_Program.id(), "uTexture");

        uKd        = glGetUniformLocation(_Program.id(), "uKd");
        uKs        = glGetUniformLocation(_Program.id(), "uKs");
        uShininess = glGetUniformLocation(_Program.id(), "uShininess");

        uLightPos_vs    = glGetUniformLocation(_Program.id(), "uLightPos_vs");
        uLightDir_vs    = glGetUniformLocation(_Program.id(), "uLightDir_vs");
        uLightCharacter_vs    = glGetUniformLocation(_Program.id(), "uLightCharacter_vs");
        uLightIntensity = glGetUniformLocation(_Program.id(), "uLightIntensity");
    }
};

I saw several topics of this error but none of them seemed to solve it.

Thanks

Lauriane
  • 41
  • 6
  • https://en.cppreference.com/w/cpp/language/copy_assignment#Implicitly-declared_copy_assignment_operator – Marek R May 19 '23 at 10:32
  • @MarekR Not 100% the correct link. This is the link to the move assignment related stuff: https://en.cppreference.com/w/cpp/language/move_assignment#Deleted_implicitly-declared_move_assignment_operator – fabian May 19 '23 at 10:36
  • `ObjectProgram& _program;` is an issue. `T has a non-static data member of a reference type;` – Marek R May 19 '23 at 10:40
  • I'm wondering how you defined `Object::Object()`, since there doesn't seem to be anything to initialize `_program` with. Note: if you need move assignment for `Object`, you need to go with a pointer (or `std::reference_wrapper`) here instead of a reference to make the member variable reassignable. – fabian May 19 '23 at 10:41
  • Does this answer your question? [C++ - Copy Assignment Operator is Implicitly Deleted](https://stackoverflow.com/questions/35299985/c-copy-assignment-operator-is-implicitly-deleted) –  May 19 '23 at 12:13
  • Side note: you can get rid of all those redundant explicit dereferences of `this` (`this->`), it's only (rarely) needed in templates to make other types dependant names (and in a few other equally rare situations). – Jesper Juhl May 19 '23 at 13:01

2 Answers2

6

Classes that have reference or const non-static data members (or non- assignable base-class sub-objects or non-static data members) are non-assignable by default, because reference is not reseatable, const is immutable and non-assignable component non-assignable. IOW these have their default operator= deleted.

We see:

class Object 
{
    /* ... */
    ObjectProgram& _program;
}

That _program is reference so default operator= of Object it is deleted. You got to provide custom operator= or not to try to assign it.

Öö Tiib
  • 10,809
  • 25
  • 44
  • So if I understood this right, I have to make a custom = operator for the Object class ? – Lauriane May 19 '23 at 10:46
  • in that custom operator= you still won't be able to change the reference – maxim1000 May 19 '23 at 10:48
  • 2
    @Lauriane Or change `ObjectProgram& _program; ` to `ObjectProgram* _program;` and use a pointer to observe the `ObjectProgram`. – Richard Critten May 19 '23 at 11:12
  • @maxim1000 Such a custom `operator=()` does not attempt to "reseat" the reference, so the reference refers to the same object through life of the containing `Object`. If that is not the behaviour sought in the assignment operator, then a reference member is the wrong choice (and one option, as Richard noted is using a pointer, since - unlike a reference - a pointer CAN be reassigned, as well as not suppressing implicit generation of an `operator=()`). – Peter May 19 '23 at 11:40
1

As mentioned in the compiler warnings the member variable with a reference type prevents any assignment operators from being implicitly defined.

ObjectProgram& _program;

Note that this does not mean the implicitly defined move constructor is deleted too. This is the reason why std::vector<Wanderer>::push_back works: If the backing storage needs to be reallocated, the existing objects are moved over to the new storage by using the move constructor with placement new.

Your options of fixing this issue are limited:

  • Make _program a pointer, std::reference_wrapper, or similar allowing for the implicilty created move constructor to be defined.
  • Change the type of gaspard to something that doesn't require the assignment operator, e.g. std::optional<Wanderer> allowing you to use std::optional<Wanderer>::emplace for the initialization.
fabian
  • 80,457
  • 12
  • 86
  • 114