C++: copyable view on an object - c++

I'm trying to make a program that deals with images, in which I have an image object and an image_view object that references a rectangle region in the image:
class image_view;
class image
{
public:
image(int width, int height);
operator image_view() const;
private:
int m_width;
int m_height;
std::vector<pixel> m_pixels;
};
class image_view
{
public:
image_view(const image& ref, point origin, int width, int height);
image_view(image_view view, point origin, int width, int height);
private:
const image& m_ref;
point m_origin;
int m_width;
int m_height;
};
However, when I tried to copy an image_view, the compiler told me that the operator= member function had been deleted because of the non-static member reference. I naively tried to make my own member function with m_ref = other.m_ref but it didn't work since m_ref is const.
I considered using a smart pointer instead of a reference, but I didn't find a way of making a smart pointer to an already existing object.
One solution I found is the following:
image_view& image_view::operator= (const image_view& other)
{
*this = image_view(other);
return *this;
}
This compiles, but is it a good idea? (I might be wrong, but I feel bad about assigning stuff to *this.) If I do that, does that mean I have to define a destructor (even though I'm not allocating anything), move constructor and move assignment operator to satisfy the rule of 5?

If you want to express a non-owning, non-null wrapper that rebinds on assignment, the easiest way to do that is to use std::reference_wrapper:
class image_view
{
public:
image_view(const image& ref, point origin, int width, int height);
image_view(image_view view, point origin, int width, int height);
private:
std::reference_wrapper<image const> m_ref;
point m_origin;
int m_width;
int m_height;
};
The default copy constructor and assignment operator will do the right thing.

Related

Default Copy Operations for Structs with Constant Members

I have a Texture struct that I am using to hold the width, height, and id number of a texture. I also have a Loader class with many static functions dedicated to loading content, such as textures. The problem arises when I try to declare an uninitialized Texture, and then initialize it later. Here is the code in Texture.h:
namespace bronze {
struct Texture {
const unsigned int id;
const float width;
const float height;
Texture() = default;
Texture(Texture&&) = default;
Texture& operator=(Texture&&) = default;
};
}
In Loader.cpp
Texture(const std::string& file, float scale) {
unsigned int id;
float width, height;
loadTextureUsingExternalLibrary(&id, &width, &height);
doThingsWithTexture(id);
return Texture{id, width, height}
}
And then in main.cpp:
#include "Loader.h"
#include "Texture.h"
using namespace bronze;
Texture tex;
int main() {
tex = Loader::loadTexture("asdf.png", 2.f);
drawTextureOnTheWindowSomehow(tex);
return 0;
}
Here are the (shortened, of course) errors I am getting (MinGW is my compiler):
error: use of deleted function 'bronze::Texture::Texture()'
Texture tex;
note: 'bronze::Texture::Texture()' is implicitly deleted because the default
definition would be ill-formed:
Texture() = default;
...complains about each member being uninitialized
error: use of deleted function 'bronze::Texture& bronze::Texture::operator=
Bronze::Texture&&)'
tex = Loader::loadTexture("asdf.png", 2.f);
note: 'bronze::Texture& bronze::Texture::operator=(bronze::Texture&&)' is
implicitly deleted because the default definition would be ill-formed:
Texture& operator=(Texture&&) = default;
...complains for each struct member that "non-static const member can't use
default assignment operator"
I have been Googling around for a while now, and cannot find anything. Perhaps it is that I do not know what to Google, I do not know. Help is appreciated!
A few parts to this
1.The default constructor doesn't work because you can't have an uninitialized const object (even primitives). For your simple case you probably just want them to be value initialized and this can be achieved easily enough:
struct Texture {
const unsigned int id{};
const float width{};
const float height{};
//...
};
2.You can't use the implicitly generated operator= for an object with const data members because that would require assigning to const objects.
struct A { const int i{}; };
A a1;
A a2(a1); // fine
a1 = a2; // not fine. can't do a1.i = a2.i since a1.i is const!
If you want to be able to assign, you'll need to use non-const data members. You cannot use the implicit operator= if you have const members* You could const_cast but that'd lead to undefined behavior and is a horrible idea (just saying it before someone mentions it in the comments).
You aren't just declaring tex, you are defining it. The point of definition requires being initialized. Trying to assign later is not initializing it.
Don't use global variables.
*unless those const members have an operator=(..) const but that'd be pretty weird
Texture is an aggregate with const members. You must provide the values during initialization.
When you return with return Texture{id, width, height} it does the aggregate initialization for you, but if you try to construct Texture the constructor could never work without initializing the const members.
So you might rather use:
Texture(unsigned int id, float width, float height) : id{id}, width{width}, height{height} {};
Also note that you may not be able to use the implicitly deleted operator=, but you may define your own.
The following program works fine with the assignment operator.
struct Texture {
const unsigned int id;
const float width;
const float height;
int other;
Texture(unsigned int id,float width,float height,int other) : id{id},width{width},height{height},other{other} {};
Texture(const Texture & rhs) : id{rhs.id},width{rhs.width},height{rhs.height} {};
Texture& operator=(const Texture& rhs)
{
other = rhs.other;
return *this;
};
};
int main()
{
Texture t0{1,2,3,0};
auto t1 = Texture(3,3,3,1);
Texture t2 = t0; // t2's constants are initialized to be the same as t0's
t2 = t1; // only the non const member data is copied
return 0;
}

How to workaround "redefinition of default parameter" in class constructor

Consider the following example:
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
A Rectangle object may be built giving (x,y) coordinates plus width and height or giving top left points pair and bottom right points pair.
While this is correct from an object oriented point of view, this is not from a compiler point of view, returning the error "member function already defined or declared"
While I normally fix this condition easily in case of member function, simply changing the name according to what it does, this is not possible for constructors.
What is the simpler and correct way to workaround this issue keeping both the way to construct the object?
Another possible solution (other than the pair suggested by #VladfromMoscow) is a static method to perform construction. This lets you give them distinct names, since their argument lists are so similar. Thisi is called the Named Constructor Idiom
class Rectangle
{
public:
static Rectangle createRectangle(int x, int y, int width, int height)
{
return Rectangle(x,y,width,height);
}
static Rectangle createRectangleCorners(int x1, int y1, int x2, int y2)
{
return Rectangle(x1,y1,x2-x1, y2-y1);
}
private:
// Doesn't have to be private, but this forces users to use the above
// constructors
Rectangle(int x, int y, int width, int height);
}
You wrote already yourself
top left points pair and bottom right points pair
So what you need is to define class Point and use this type in the constructor declaration.
Otherwise the constructors are declared like
class Rectangle{
Rectangle(int, int, int, int);
Rectangle(int, int, int, int);
};
As you see these declarations do not make sense even if you will write multiline comments.:)
Another approach is to declare the first constructor like
class Rectangle{
Rectangle(int x, int y, unsigned int width, unsigned int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
However this approach is unsafe because each integer literal specified as the third or fourth argument must be casted.
Instead of the class Point you could use standard class std::pair. For example
#include <utility>
//...
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle( const std::pair<int, int> &topLeft, const std::pair<int, int> &bottomRight);
};
Another way on how to solve this problem is by using Tag dispatching:
Instead of using methods with different names, give them a new parameter, e.g.,
struct useCorners {};
struct useDimension {};
class Rectangle
{
Rectangle(useCorners, int topLeft, int topRight, int bottomLeft, int bottomRight)
{ ...
}
Rectangle(useDimension, int topLeft, int topRight, int width, int height)
{ ...
}
};

C++ Destructor (With Code Example)

I have just switched from Java to C++ and everything is going pretty well so far. The language is kind of hard, but I feel as though I am catching on. I have a question about destructors though, and for this I will supply my current code in hopes that someone could provide some clarification on what and how I should proceed.
I am writing a game in OpenGL and have created Three classes: Vector3D, Dimension3D, and Cuboid. My problem starts like this, my cuboid has an instance of both Vector3D and Dimension3D, which you will soon see. I need to know how (the exact routine) of what happens to my Cuboid class once it is flagged for deletion. Or more precisely, if i need to explicitly destroy both the Vector3D and Dimension3D instance when such an event occurs. I hope I articulated this question adequately enough.
Here are my classes.
(Vector3D.cpp)
#include "Vector3D.h"
Vector3D::Vector3D(){
}
Vector3D::Vector3D( const float& x , const float& y , const float& z ){
this->x = x;
this->y = y;
this->z = z;
}
Vector3D::~Vector3D(){
}
void Vector3D::setX( const float& x ){
this->x = x;
}
void Vector3D::setY( const float& y ){
this->y = y;
}
void Vector3D::setZ( const float& z ){
this->z = z;
}
float Vector3D::getX(){
return x;
}
float Vector3D::getY(){
return y;
}
float Vector3D::getZ(){
return z;
}
(Vector3D.h)
#ifndef NE3_Vector3D_H_
#define NE3_Vector3D_H_
class Vector3D{
public:
Vector3D();
Vector3D( const float& , const float& , const float& );
~Vector3D();
void setX( const float& );
void setY( const float& );
void setZ( const float& );
void setPosition( const float& , const float& , const float& );
float getX();
float getY();
float getZ();
float x;
float y;
float z;
private:
// Private Members Go Here
};
#endif // NE3_Vector3D_H_
(Dimension3D.cpp)
#include "Dimension3D.h"
Dimension3D::Dimension3D(){
}
Dimension3D::Dimension3D( const float& width , const float& height , const float& depth ){
this->width = width;
this->height = height;
this->depth = depth;
}
Dimension3D::~Dimension3D(){
}
void Dimension3D::setWidth( const float& width ){
this->width = width;
}
void Dimension3D::setHeight( const float& height ){
this->height = height;
}
void Dimension3D::setDepth( const float& depth ){
this->depth = depth;
}
float Dimension3D::getWidth(){
return width;
}
float Dimension3D::getHeight(){
return height;
}
float Dimension3D::getDepth(){
return depth;
}
(Dimension3D.h)
#ifndef NE3_Dimension3D_H_
#define NE3_Dimension3D_H_
class Dimension3D{
public:
Dimension3D();
Dimension3D( const float& , const float& , const float& );
~Dimension3D();
void setWidth( const float& );
void setHeight( const float& );
void setDepth( const float& );
void setSize( const float& , const float& , const float& );
float getWidth();
float getHeight();
float getDepth();
float width;
float height;
float depth;
private:
// Private Members Go Here
};
#endif // NE3_Dimension3D_H_
And lastly, my Work in progress Cuboid.cpp and Cuboid.h
(Cuboid.cpp)
#include "Cuboid.h"
Cuboid::Cuboid(){
}
Cuboid::Cuboid(const Vector3D& location, const Dimension3D& dimension){
this->location = location;
this->dimension = dimension;
}
Cuboid::~Cuboid(){
// Do i do delete both location and dimension here?
}
void Cuboid::drawImmediate(){
}
void Cuboid::drawVBO(){
}
(Cuboid.h)
#ifndef NE3_CUBOID_H_
#define NE3_CUBOID_H_
#include "Vector3D.h"
#include "Dimension3D.h"
class Cuboid{
public:
Cuboid();
Cuboid( const Vector3D& , const Dimension3D& );
~Cuboid();
void drawImmediate();
void drawVBO();
Vector3D location;
Dimension3D dimension;
private:
};
#endif // NE3_CUBOID_H_
I left a comment in Cuboid.cpp within the destructor. I want to know if I should be deleting the Vector3D and Dimension3D there, and an example showing the best way to do this. IE: Any common conventions that express this functionality.
If my question is not adequate, I will be more than happy to provide further clarification. Also, I am sure that there are other questions like this, however, I need to see it in my own code to fully grasp it. (weird learning style), so please forgive me if this turns into a duplicate.
In this particular case you do not need any explicit destruction code.
The reason for this is that you are using direct members:
class Cuboid {
public:
Vector3D location;
};
This means that the Vector3D object is embedded into the memory of the Cuboid and automatically allocated and released together with the Cuboid.
It would be a different case if you had a pointer to the object as member (e.g. Vector3D *location) instead of the member itself. In that case, you would also have to explicitly allocate memory for the location, as well as explicitly release it in the destructor.
Since you are just starting with C++, a beginner rule of thumb that you can use is that you explicitly delete only what you explicitly allocate.
Since you haven't allocated the Vector3D yourself (for example via new), you shouldn't delete it.
The situation would have been different, if your code looked like this,
// Cuboid.cpp
Cuboid::Cuboid(){
location = new Vector3d;
}
Cuboid::~Cuboid(){
delete location; // now this is necessary
}
// Cuboid.hpp
class Cuboid {
private:
Vector3D* location; // using a raw pointer here, this can be different for scoped/RAII pointer, unique_ptr
};
Also, consider making the members private, encapsulation is important in C++ as much as it is in Java.
Then as you progress with C++ you will encounter RAII, a slightly more advanced topic, that invalidates the rule of thumb above in the sense that you will use the language constructs, or your own scoped/RAII classes to handle the deallocation for you in a deterministic way. For example, in the following case,
std::unique_ptr<Vector3D> location(new Vector3D);
you won't need to deallocate location yourself, it will be automatically deallocated by the C++ standard library when the unique_pointer will go out of the current scope block, or when the enclosing object, of which location is a member, will be deallocated.
If you allocated the Vector3D object and the Dimension3D object dynamically in the constructor of class Cuboid, then you would need to delete them in the destructor of class Cuboid:
Cuboid::Cuboid(const Vector3D& location, const Dimension3D& dimension){
this->location = new Vector3D(location);
this->dimension = new Dimension3D(dimension);
}
Cuboid::~Cuboid(){
delete location;
delete dimension;
}
But since this is not the case in your code, you do not need to delete these objects.
Whether you allocate a Cuboid object dynamically with Cuboid* x = new Cuboid(...), or statically with Cuboid x(...), these two member objects (location and dimension) will be implicitly destroyed as soon as the (empty) destructor of class Cuboid is invoked.
Cuboid's location and dimension members do not need to be deleted in its constructor. Their destructors are invoked automatically when a Cuboid instance is destructed since you are not explicitly managing their memory allocation, i.e. you didn't use "new" when creating them.
Further, given the code you've shown, both the Vector3D and Dimension3D classes don't need to do any manual resource management in their destructors either. Basically, if you aren't using new to allocate memory for any objects you typically don't need to worry about releasing them.
No you do not need to deallocate the members location and dimension as they are automatic objects whose lifetimes is automatically controlled. They will automatically be destroyed when the class Cuboid is destroyed.
It is in fact undefined behaviour to perform a delete on e.g. a pointer to a local automatic object.
As a best practice you should not use delete in C++ (unless you know what you're doing). If you need to dynamically allocate memory (and the containers in the standard library does not do the job) then you should use a smart pointer, as std::shared_ptr, that can handle the deallocation for you (see RAII).

Rectangle class with three constructors

I need to complete the Rectangle class. Write 3 constructors and a destructor to satisfy the main() below. Use constructor initializers for each constructor.
This is what is done:
class Rectangle
{
float* length;
float* width;
...
???
...
};
int main()
{
Rectangle r1;
Rectangle r2(4.5,2.3);
Rectangle r3(r2);
}
This is how I filled up the rectangle class:
class rectangle
{
private:
float* length;
float* width;
public:
rectangle(); //default constructor
rectangle(double w, double l); //constructor with parameters
rectangle(const rectangle&); //copy constructor
~rectangle(void);
double getWidth(void);
double getLength(void);
double perimeter(void) const;
double area(void) const;
};
...........
...........
...........
int main()
{
rectangle r1;
rectangle r2(4.5,2.3);
rectangle r3(r2);
//statements
}
I just want to know if am doing it right or wrong. Can anyone see if am missing smth or need to add to rectanglr class?!
I think that you are doing wrong because the definition
Rectangle r2(4.5,2.3);
does not have a corresponding constructor. Also take into account that the class in the assignment is named as Rectangle not rectangle.:)
I think that instead of length and width (why did you declare them as pointers?!) you should define four data members that will denote four points of the rectangle.
The declaration and the uses of the three constructors (default constructor, a custom constructor, and a copy constructor) look reasonable. Storing pointers to float does not look reasonable, however: you should just store floats (I would actually store doubles unless I have a reason to assume that there are a huge mount of rectangles). When storing floats, there is actually no need to have a copy constructor or a destructor. If you insist in storing float* and, thus, allocate memory, you shall also implement a copy assignment:
rectangle& rectangle::operator= (rectangle other) {
other.swap(*this);
return *this;
}
void rectangle::swap(rectangle& other) {
std::swap(this->length, other.length);
std::swap(this->width, other.width);
}

Constructor in implementation versus header

The constructor should, to my knowledge, be defined in the implementation file but I've only been able to find examples with the class inside one main file instead of split into a .h and .cpp file
All I need to know is if my following code is separated in an acceptable manner..
Entity.h:
using namespace std;
class cEntity {
private:
/*-----------------------------
----------Init Methods---------
-----------------------------*/
int *X, *Y;
int *Height, *Width;
public:
/*-----------------------------
----------Constructor----------
-----------------------------*/
cEntity (int,int, int, int);
/*-----------------------------
----------Destructor-----------
-----------------------------*/
~cEntity ();
/*-----------------------------
----------Set Methods----------
-----------------------------*/
/*Set X,Y Methods*/
void setX(int x){*X=x;};
void setY(int y){*Y=y;};
void setXY(int x, int y){*X=x; *Y=y;};
/*Set Height, Width Methods*/
void setHeight(int x){*Height=x;};
void setWidth(int x){*Width=x;};
void setDimensions(int x, int y){*Height=x; *Width=y;};
/*-----------------------------
----------Get Methods----------
-----------------------------*/
/*Get X,Y Methods*/
int getX(){return *X;};
int getY(){return *Y;};
/*Get Height, Width Methods*/
int getHeight(){return *Height;};
int getWidth(){return *Width;};
};
and Entity.cpp:
#include "Entity.h"
cEntity::cEntity (int x, int y, int height, int width) {
X,Y,Height,Width = new int;
*X = x;
*Y = y;
*Height = height;
*Width = width;
}
cEntity::~cEntity () {
delete X, Y, Height, Width;
}
I would also like to say thanks to everyone for being so helpful, especially on my first question!
cEntity::cEntity (int x, int y, int height, int width) {
is correct
X,Y,Height,Width = new int;
not so much. That sets Width to a new int, but not the rest. You probably intended:
X = new int(x);
Y = new int(y);
Height = new int(height);
Width = new int(width);
Note that this method of construction will not work for objects without assignment/copy, like references. For some objects, it's also slower than constructing them in place. As such, the preferred way to construct is like so:
cEntity::cEntity (int x, int y, int height, int width) {
:X(new int(x))
,Y(new int(y))
,Height(new int(height))
,Width(new int(width))
{}
This is better, but if any exceptions are thrown, you'll have to somehow deallocate the ones that were allocated. Better is to make each of those members a std::unique_ptr<int>, so they'll deallocate themselves and save you many headaches.
Yes, it's OK.
However, there is a problem with your constructor and destructor.
What your code actually does is allocating one int and your destructor deallocates one int also.
Anyway, there is no need to use pointers here.
Somewhat better implementation (if we don't use smart pointers), could be:
[Entity.h]
private:
/*Private fields*/
int X, Y;
int Height, Width;
[Entity.cpp]
cEntity::cEntity (int x, int y, int height, int width) {
X = x;
Y = y;
Height = height;
Width = width;
}
cEntity::~cEntity () {
}
And one more thing. Try to avoid using namespace std; in your header files. If you do, you force those who include your header to use this using statement and it can provoke namespace clashes.
Your separation is fine. The implementations of those functions is wrong, but you've separated them from the declaration suitably. (They don't allocate or free as many objects as you think they do.)
Yes. For the separation at least, that's generally the best way to do it.
As for the actual implementation you have some issues. I am not really sure what you are trying to do with the constructor or if you have the correct data types for the class member variables but something seems off.
Any method defined in the class directly is implicitly inlined, including the constructor.
I.e.
class MyClass
{
public:
MyClass() {};
};
defines an inline constructor, which may (or may not) improve your code performance,
Whereas
class MyClass
{
public:
MyClass();
};
MyClass::MyClass()
{
};
is not inlined, and therefore won't have those benefits. Both options are correct C++ though.
Just my 2 cents.
P.S And yes, when you decide to store pointers inside a class in this manner, you open a Pandora box.