Initializing C++ const fields after the constructor - c++

I want to create an immutable data structure which, say, can be initialized from a file.
class Image {
public:
const int width,height;
Image(const char *filename) {
MetaData md((readDataFromFile(filename)));
width = md.width(); // Error! width is const
height = md.height(); // Error! height is const
}
};
What I could do to fix the problem is
class Image {
MetaData md;
public:
const int width,height;
Image(const char *filename):
md(readDataFromFile(filename)),
width(md.width()),height(md.height()) {}
};
However
It forces me to save MetaData as a field in my object. Which I don't always want.
Sometimes the logic in the constructor is much more complex than a single read (say, error handling can take a few lines)
So the only solution I thought of is along the lines of
class A {
int stub;
int init(){/* constructor logic goes here */}
A():stub(init)/*now initialize all the const fields you wish
after the constructor ran */{}
};
Is there a better idea? (In Java, you're allowed initializing finals in the constructor).

You could move width and height into one type and move the initialization code into an initialization helper function:
// header:
struct Size {
int width, height;
Size(int w, int h) : width(w), height(h) {}
};
class Image {
const Size size; // public data members are usually discouraged
public:
Image(const char *filename);
};
// implementation:
namespace {
Size init_helper(const char* filename) {
MetaData md((readDataFromFile(filename)));
return Size(md.width(), md.height());
}
}
Image::Image(const char* filename) : size(init_helper(filename)) {}

You can simply use the NamedConstructor idiom here:
class Image
{
public:
static Image FromFile(char const* fileName)
{
MetaData md(filename);
return Image(md.height(), md.width());
}
private:
Image(int h, int w): mHeight(h), mWidth(w) {}
int const mHeight, mWidth;
};
One of the main advantage of Named Constructors is their obviousness: the name indicates you are building your object from a file. Of course it's slightly more verbose:
Image i = Image::FromFile("foo.png");
But that never troubled me.

If it was C++0x, I would recommend this (delegating constructors):
class Image
{
public:
const int width, height;
Image(const char* filename) : Image(readDataFromFile(filename)) { }
Image(const MetaData& md) : width(md.width()), height(md.height()) { }
};

You should add inline getters for the width and height instead of public const member variables. The compiler will make this solution as fast as the original try.
class Image {
public:
Image(const char *filename){ // No change here
MetaData md((readDataFromFile(filename)));
width = md.width();
height = md.height();
}
int GetWidth() const { return width; }
int GetHeight() const { return height; }
private:
int width,height;
};
P.S.: I used to write private things at the end because they are less important for the user of the class.

First, you should understand the constructor body is just for running code to complete initializing your object as a whole; the members must be completely initialized before the body is entered.
Ergo, all members are initialized in an (implicit unless made explicit) initialization list. Clearly, const variables must be initialized in the list because once you enter the body, they are already suppose to be initialized; you'd simply be trying to assign them.
Generally, you don't have const members. If you want those members to be immutable, just don't give any public access to them that could change them. (Also, having const members make your class non-assignable; typically unnecessarily.) Going this route easily fixes your problem, as you'd just assign them values in the body of the constructor like you wish.
A method to do what you want while maintaining const could be:
class ImageBase
{
public:
const int width, height;
protected:
ImageBase(const MetaData& md) :
width(md.width()),
height(md.height())
{}
// not meant to be public to users of Image
~ImageBase(void) {}
};
class Image : public ImageBase
{
public:
Image(const char* filename) : // v temporary!
ImageBase(MetaData(readDataFromFile(filename)))
{}
};
I don't think this route is worth it.

You could cast away the constness in the constructor:
class Image {
public:
const int width,height;
Image(const char *filename) : width(0), height(0) {
MetaData md(readDataFromFile(filename));
int* widthModifier = const_cast<int*>(&width);
int* heightModifier = const_cast<int*>(&height);
cout << "Initial width " << width << "\n";
cout << "Initial height " << height << "\n";
*widthModifier = md.GetWidth();
*heightModifier = md.GetHeight();
cout << "After const to the cleaners " << width << "\n";
cout << "After const to the cleaners " << height << "\n";
}
};
That would achieve what you want to do but I must say I personally would stay away from that because it causes undefined behavior according to the standard (excerpt from cppreference)
const_cast makes it possible to form a reference or pointer to
non-const type that is actually referring to a const object ...
Modifying a const object through a non-const
access path ... results in undefined behavior.
I would fear any public data members(at least in regarding your particular example). I would go with Georg's approach or make the data private and provide only the getter.

How about passing MetaData as an argument to the constructor. This gives a lot of benefits:
a) The constructor interface makes it clear about the dependency on MetaData.
b) It facilitates testing of the Image class with different types of MetaData (subclasses)
So, I would probably suggest similar to follows:
struct MD{
int f(){return 0;}
};
struct A{
A(MD &r) : m(r.f()){}
int const m;
};
int main(){}

I'd use a static method:
class Image {
public:
static Image* createFromFile( const std::string& filename ) {
//read height, width...
return new Image( width, height );
}
//ctor etc...
}

class A
{
public:
int weight,height;
public:
A():weight(0),height(0)
{
}
A(const int& weight1,const int& height1):weight(weight1),height(height1)
{
cout<<"Inside"<<"\n";
}
};
static A obj_1;
class Test
{
const int height,weight;
public:
Test(A& obj = obj_1):height(obj.height),weight(obj.weight)
{
}
int getWeight()
{
return weight;
}
int getHeight()
{
return height;
}
};
int main()
{
Test obj;
cout<<obj.getWeight()<<"\n";
cout<<obj.getHeight()<<"\n";
A obj1(1,2);
Test obj2(obj1);
cout<<obj2.getWeight()<<"\n";
cout<<obj2.getHeight()<<"\n";
return 0;
}
As far my understanding i think this mechanism will work.

This is one of my least favorite aspects of C++ when compared to Java. I'll use an example I was working on when I needed to solve this problem.
What follows is the equivalent of a readObject method. It deserializes a Video key from a provided file path.
#include <fstream>
#include <sstream>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
using namespace std;
using namespace boost::filesystem;
using namespace boost::archive;
class VideoKey
{
private:
const string source;
const double fps;
const double keyFPS;
const int numFrames;
const int width;
const int height;
const size_t numKeyFrames;
//Add a private constructor that takes in all the fields
VideoKey(const string& source,
const double fps,
const double keyFPS,
const int numFrames,
const int width,
const int height,
const size_t numKeyFrames)
//Use an initializer list here
: source(source), fps(fps), keyFPS(keyFPS), numFrames(numFrames), width(width), height(height), numKeyFrames(numKeyFrames)
{
//Nothing inside this constructor
}
public:
//Then create a public static initializer method that takes in
//the source from which all the fields are derived
//It will extract all the fields and feed them to the private constructor
//It will then return the constructed object
//None of your fields are exposed and they are all const.
const static VideoKey create(const path& signaturePath)
{
const path keyPath = getKeyPath(signaturePath);
ifstream inputStream;
inputStream.open(keyPath.c_str(), ios::binary | ios::in);
if (!inputStream.is_open())
{
stringstream errorStream;
errorStream << "Unable to open video key for reading: " << keyPath;
throw exception(errorStream.str().c_str());
}
string source;
double fps;
double keyFPS;
int numFrames;
int width;
int height;
size_t numKeyFrames;
{
binary_iarchive inputArchive(inputStream);
inputArchive & source;
inputArchive & fps;
inputArchive & keyFPS;
inputArchive & numFrames;
inputArchive & width;
inputArchive & height;
inputArchive & numKeyFrames;
}
inputStream.close();
//Finally, call your private constructor and return
return VideoKey(source, fps, keyFPS, numFrames, width, height, numKeyFrames);
}

Related

Inheriting Struct in C++

I have a class, Table, which contains a member height. The value of height should be either an int or point to an object which has additional data.
The purpose here is that the user can either input a straight value, or choose a predefined value (identified by its ID) which can be shared by multiple Table objects.
This is a way I think I could achieve this functionality.
1) Create a base class Height.
2) Have two subclasses StraightHeight and PredefinedHeight
StraightHeight would simply contain an integer with the height (with getter and setter), and PredefinedHeight would contain the additional data:
class PredefinedHeight : public Height
{
public:
void setHeight(int height);
void setId(int id);
void setName(std::string name);
int getHeight();
int getId();
std::string getName();
private:
int height;
int id;
std::string name;
};
Inside Table, the height member would be of type Height.
I think this would work in practice, however I have another issue. When it comes to displaying this data, if height is a straight value (of type StraightHeight), it should just display the int height. If it is a PredefinedHeight, it should display the id and name as well. I could have a virtual method std::string getData() in both classes which returns the necessary data but it feels messy relying on the classes to format the string, etc.
Alternatively I could use a dynamic cast, but worry that it may be bad practise in this case.
Or for simplicity sake, not bother with inheritance and just have one class for Height. If it's a straight value, just leave the additional members empty.
Does anyone have a better suggestion?
Note: This is an updated, rewritten answer. The prior version is available in the edit history.
Let's look at it from data modeling perspective: Table has a property height. That property can either be owned by the Table, or can come from another source. The simplest way one could think of would be to use a pointer to a const object. The pointer should be to a const, since the height may be a preset, and those shouldn't be changeable via the Table object.
class Table {
int m_myHeight;
const int *m_height = &m_myHeight;
public:
int height() const { return *m_height; }
void setHeight(int newHeight) {
m_height = &m_myHeight;
m_myHeight = newHeight;
}
void setPresetHeight(const int &preset)
{
m_height = &preset;
/* this line is optional */ m_myHeight = *m_height;
}
};
class PresetHeights {
std::vector<int> m_data;
public:
const int &getPreset(int index);
};
This will work just fine, but you may wish to have some additional properties assigned to the preset - properties that the "embedded" height of the Table object doesn't have. For example, the preset can have a name, etc.
This can be done by holding a reference to either "just" a height, or to a height preset. Since the identifier of a height preset is used to index the identifier in a presets table, it probably makes sense to make the id value private, and only accessible via the presets table. This gives the power over ids to the presets table, and gives some freedom in how the table is implemented.
The example that follows is written in C++17, and can be tried out on godbolt.
#include <string>
#include <variant>
struct Height {
int value;
Height(int value) : value(value) {}
operator int() const { return value; }
};
struct HeightPreset : Height {
using Id = int;
private:
Id id; // the unique identifier of this preset
friend class HeightPresets;
friend int main(); // test harness
public:
std::string name; // name of this preset
template <typename Name>
HeightPreset(Id id, int value, Name &&name) :
Height(value), id(id), name(std::forward<Name>(name)) {}
};
The Table uses std::variant to hold either no height value (std::monostate), or a Height, or a HeightPreset:
#include <functional>
class Table {
using preset_t = std::reference_wrapper<const HeightPreset>;
std::variant<std::monostate, Height, preset_t> m_height;
public:
std::optional<Height> height() const {
if (auto *customHeight = std::get_if<Height>(&m_height))
return *customHeight;
else if (auto *presetHeight = std::get_if<preset_t>(&m_height))
return std::get<preset_t>(m_height).get();
else
return {};
}
void setHeight(Height newHeight)
{ m_height = newHeight; }
void setHeightPreset(const HeightPreset &preset)
{ m_height = std::cref(preset); }
bool hasPresetHeight() const { return m_height.index() == 2; }
const HeightPreset &presetHeight() const
{ return std::get<preset_t>(m_height).get(); }
};
Presets Iterable By Value of Type HeightPreset
The presets are a map from HeightPreset::Id to HeightPreset. But first, we need an iterator adapter to let us iterate the preset values - hiding the implementation detail that we use a map whose iterated values are std::pair, not HeightPreset.
#include <map>
template <class K, class V, class C, class A>
class map_cvalue_iterator
{
typename std::map<K, V, C, A>::const_iterator it;
public:
map_cvalue_iterator(typename std::map<K,V>::const_iterator it) : it(it) {}
map_cvalue_iterator(const map_cvalue_iterator &o) : it(o.it) {}
auto &operator=(const map_cvalue_iterator &o) { it = o.it; return *this; }
auto operator++(int) { auto val = *this; ++it; return val; }
auto &operator++() { ++it; return *this; }
auto operator--(int) { auto val = *this; --it; return val; }
auto &operator--() { --it; return *this; }
const V& operator*() const { return it->second; }
const V* operator->() const { return it->second; }
bool operator==(map_cvalue_iterator o) const { return it == o.it; }
bool operator!=(map_cvalue_iterator o) const { return it != o.it; }
};
template <class M>
using map_cvalue_iterator_type
= map_cvalue_iterator<typename M::key_type, typename M::mapped_type,
typename M::key_compare, typename M::allocator_type>;
The presets are a thin wrapper around std::map:
class HeightPresets {
public:
using Id = HeightPreset::Id;
HeightPresets(std::initializer_list<HeightPreset> presets)
{
for (auto &preset : presets)
m_presets.insert({preset.id, preset});
}
auto &get(Id id) const { return m_presets.at(id); }
Id getIdFor(const HeightPreset &preset) const
{ return preset.id; }
auto begin() const { return map_cvalue_iterator_type<map_t>(m_presets.cbegin()); }
auto end() const { return map_cvalue_iterator_type<map_t>(m_presets.cend()); }
private:
using map_t = std::map<Id, HeightPreset>;
map_t m_presets;
};
The simple test harness that demonstrates the use of those types:
#include <cassert>
int main() {
const HeightPresets presets{
{1, 5, "A Fiver"},
{2, 10, "A Tenner"}
};
Table aTable;
assert(!aTable.height());
// The table has no height by default
aTable.setHeight(10);
assert(!aTable.hasPresetHeight());
// The height was not a preset
assert(aTable.height() == 10);
// The height was retained
for (auto &preset : presets)
{
aTable.setHeightPreset(preset);
assert(aTable.hasPresetHeight());
// The height was preset
assert(aTable.height() == preset);
// The height has the expected preset's value
assert(presets.getIdFor(aTable.presetHeight()) == preset.id);
// The height has the expected preset's identifier
assert(aTable.presetHeight().name == preset.name);
}
}
Presets Iterable by std::pair<HeightPreset::Id, HeightPreset>
If you wish not to use the iterator adapter, it can be removed. See below, and also try it out on godbolt.
#include <map>
class HeightPresets {
public:
using Id = HeightPreset::Id;
HeightPresets(std::initializer_list<HeightPreset> presets)
{
for (auto &preset : presets)
m_presets.insert({preset.id, preset});
}
auto &get(Id id) const { return m_presets.at(id); }
Id getIdFor(const HeightPreset &preset) const
{ return preset.id; }
auto begin() const { return m_presets.cbegin(); }
auto end() const { return m_presets.cend(); }
private:
using map_t = std::map<Id, HeightPreset>;
map_t m_presets;
};
And the test harness:
#include <cassert>
int main() {
const HeightPresets presets{
{1, 5, "A Fiver"},
{2, 10, "A Tenner"}
};
Table aTable;
assert(!aTable.height());
// The table has no height by default
aTable.setHeight(10);
assert(!aTable.hasPresetHeight());
// The height was not a preset
assert(aTable.height() == 10);
// The height was retained
for (auto &presetPair : presets)
{
auto &preset = presetPair.second;
aTable.setHeightPreset(preset);
assert(aTable.hasPresetHeight());
// The height was preset
assert(aTable.height() == preset);
// The height has the expected preset's value
assert(presets.getIdFor(aTable.presetHeight()) == preset.id);
// The height has the expected preset's identifier
assert(aTable.presetHeight().name == preset.name);
}
}
The value of height should be either an int or point to a struct which has additional data
This is called a sum type a.k.a. a tagged union.
C++ has a standard template for that: std::variant from the standard <variant> header. You probably want to use some smart pointer inside.
If you cannot use that header, re-implement it using some union inside your class (with another member discriminating that union, inspired by this), but don't forget to follow the rule of five.
I recommend reading more about C++. First, Programming -- Principles and Practice Using C++ and later the C++11 standard n3337.

Creating Vector elements without calling a constructor

Lets say I have two classes car and service. Is it possible to create the elements for both vector objects(note: I don't know if is actually refereed to as vector objects), of the car and service classes. Once both elements are created I would only like the car class constructor to be called later to have the service constructor called to get the user information?
Also if it is possible is it possible without having to change the Service constructor to a method?
using namespace std; // I know this is not the best, prof wants us to use it
class Car { Car() { //Get data from user } };
class Service { Service(){ //Get data from user } };
int main () {
int num;
vector<Car> car;
vector<Service> service;
car.push_back(Car{});
service.push_back();
for (int i = 0; i < car.size(); i++)
car[i].display(i);
cout << endl << car.size() + 1 << ". exit";
cin >> num;
service[num].Service::Service();
}
I would recommend using a std::map instead of std::vector which choice naturally follows from your task. By using it, you will be storing valid Service elements only.
map<int,Service> service;
car.push_back(Car{});
for (int i = 0; i < car.size(); i++)
car[i].display(i);
cout << endl << car.size() + 1 << ". exit";
cin >> num;
service[num]; //Service constructor will be called
I'm thinking you are looking for something like this:
class Car {
private:
std::string _make;
std::string _model;
std::string _vinNumber;
std::size_t _year;
public:
Car() : _year( 0 ) {} // default
Car( const std::string& make, const std::string& model,
const std::string& vinNumber, const std::size_t& year ) :
_make( make ), _model( model ),
_vinNumber( vinNumber ), _year( year ) {
}
void setCarInfo( const std::string& make, const std::string& model,
const std::string& vinNumber, const std::size_t& year ) {
_make = make;
_model = model;
_vinNumber = vinNumber;
_year = year;
}
std::string makeOf() const { return _make; }
std::string modelOf() const { return _model; }
std::string vinNumberOf() const { return _vinNumber; }
std::size_t yearOf() const { return _year; }
};
class Service {
private:
std::string _dealership;
std::size_t _currentMiles;
public:
Serivce() {}
std::string dealershipOf() const { return _dealership; }
std:size_t currentMilesOf() const { return _currentMiles; }
void setOrChangeDealership( const std::string& dealership ) {
_dealership = dealership;
}
void setOrChangeCurrentMiles( std::size_t miles ) {
_currentMiles = miles;
}
void setOrChangeCurrentMiles( const std::size_t& miles ) {
_currentMiles = miles;
}
};
int main() {
std::vector<Car> cars;
std::vector<Service> services;
// you can add Car to vector by either default constructor
// to be filled out later or by user defined constructor
cars.push_back( Car( "Honda", "Civic", "75273250323XMD252AG9", 2017 ) );
// or
cars.push_back( Car() );
// then you can at some point in time update elements in container
cars[i].setCarInfo( "Dodge", "Charger", "9259356M325D2680A217B", 2015 );
// As with the service class there is only a "default" constructor
services.push_back( Service() );
// Service's members will have to be updated manually and later.
return 0;
}
Regardless of what container you use, or even if you have a single instance of a class object; a CTOR for that class will be called. The only way that one will not is if either A: you declare it as protected or private in the class the prevents the class from being declared which is used with inheritance and polymorphism, or if you declare the constructor as a deleted function: SomeClass() = delete. There is no possible way to have a class instance without its constructor being called either implicitly by the compiler or explicitly by you.
Even something as simple as this:
class A {
public:
int x;
};
int main() {
A a;
a.x = 5;
return 0;
}
The line A a; behind the scenes the compiler will invoke A() on a so it would actually look like this:
A a();
Using its default constructor.
Since C++11, you have the list-initialization for vector and other containers.
http://en.cppreference.com/w/cpp/language/list_initialization
Which means, you can put an enumeration of elements in a vector while initialization.
You can use your own class constructor in it:
std::vector<Car> cars {Car(...), Car(...), Car(...)}; //C++11
Since I can't comment your question yet, is it what you expected?

Unique_Ptr: Attemting To Reference A Deleted Function

So I'm working on a school project right now in C++, although I'm not too familiar with the language yet.
The whole project is divided in several Milestones.
1: Reading a list with different Types of Creatures and storing them in a vector
2: Reading a TGA-File and storing it in a class.
...
5: Reading a TGA-Picture for every read Creature-Type and storing it for further use. (Printing on GUI, Remove/add)
So I thought it is a good idea to store the picture for each type in the class itself, as it should only be loaded once.
The load() function in my TGAPicture class will return std::unique_ptr so I added the type as an argument in my CreatureType class.
After doing that, I got several error like this:
Error C2280 'biosim::CreatureType::CreatureType(const biosim::CreatureType &)': attempting to reference a deleted function bio-sim-qt E:\Development\C++\bio-sim-qt\bio-sim-qt\qtmain.cpp 58 1
Error (active) function "biosim::CreatureType::CreatureType(const biosim::CreatureType &)" (declared implicitly) cannot be referenced -- it is a deleted function bio-sim-qt e:\Development\C++\bio-sim-qt\bio-sim-qt\Model.cpp 15 26
So I read about 10 questions with similar titles like mine and every one pointed out, that you cant copy unique_ptr and suggested solutions like using std::move() or returning a reference.
Although I tried to use these to fix my problem, I wasn't able to do it in the slightest, probably because I'm pretty new to C++ and have never worked with unique pointers.
This is the code, that seems relevant to me:
/**
* #class CreatureType
* Object of the various CreatureTypes ingame
*/
class CreatureType {
private:
std::string name;
int strengh;
int speed;
int lifespan;
std::vector<std::string> attributes;
std::string path;
std::unique_ptr<TGAPicture> picture; //What I tried to add in order to stre my pictures
public:
CreatureType(const std::string& name
, int strengh, int speed, int lifespan
, const std::vector<std::string>& basic_strings
, const std::string& path);
/**
* Initializes list with CreatureTypes by reading from a .txt-File
*/
static CreatureList load(const std::string& file);
/**
* Printing Data in various ways
*/
void getInfo() const;
void getInfoInOneLine() const;
std::string getName() const;
int getStrengh() const;
int getSpeed() const;
int getLifespan() const;
std::vector<std::string> getAttributes() const;
std::string getPath() const;
};
}
CreatureType::CreatureType(const std::string& name
, int strengh, int speed, int lifespan
, const std::vector<std::string>& basic_strings
, const std::string& path)
: name(name),
strengh(strengh),
speed(speed),
lifespan(lifespan),
attributes(basic_strings),
path(path),
picture(TGAPicture::loadPicture(Reference::PicturePath::creatureBasePath + path)){ }
/**
* Implementation Notes:
* - Does a line not fullfill the requirenments, it will be ignored
* - #see Formation
* - Prints data with std::cout
*/
CreatureList CreatureType::load(const std::string& file) {
CreatureList creatureList;
std::ifstream fileStream; //Datei-Handle
int lineNumber = 0;
int correctLinesRead = 0;
fileStream.open(file, std::ios::in);
if (!fileStream.is_open()) {
throw FileNotFoundException(file);
}
logger << INFO << "Einlesevorgang wird gestartet\n";
//One line per loop
while (!fileStream.eof()) {
bool skipLine = false;
std::string line;
getline(fileStream, line);
lineNumber++;
... //Checking if data is valid
//Every Parameter does exist and is valid
creatureList.push_back(CreatureType(creatureArgs[0]
, strengh, speed, lifespan
, attributes, creatureArgs[5]));
correctLinesRead++;
}
return creatureList;
}
TGAPicture:
//no padding bytes
#pragma pack( push, 1 )
/**
* #struct TGAHeader
* Represents the standard TGA-Header.
*/
struct TGAHeader {
char idLength;
char colourmapType;
char imagetype;
short colourmapStart;
short colourmapLength;
char colourmapBits;
short xOrigin;
short yOrigin;
short width;
short height;
char bits;
char descriptor;
};
#pragma pack( pop )
/**
* #struct RGBA
* Represents a Pixel with a red, green, blue and possibly alpha value
*/
struct RGBA {
std::uint8_t B, G, R, A;
};
/**
* #class TGAPicture
* Class used to represent TGA-Files, that are used in the program
*/
class TGAPicture {
public:
TGAPicture(const TGAPicture& other)
: pixel(other.pixel),
header(other.header),
width(other.width),
height(other.height),
size(other.size),
bitsPerPixel(other.bitsPerPixel) {}
TGAPicture(TGAPicture&& other) noexcept
: pixel(std::move(other.pixel)),
header(std::move(other.header)),
width(other.width),
height(other.height),
size(other.size),
bitsPerPixel(other.bitsPerPixel) {}
TGAPicture& operator=(const TGAPicture& other) {
if (this == &other)
return *this;
pixel = other.pixel;
header = other.header;
width = other.width;
height = other.height;
size = other.size;
bitsPerPixel = other.bitsPerPixel;
return *this;
}
TGAPicture& operator=(TGAPicture&& other) noexcept {
if (this == &other)
return *this;
pixel = std::move(other.pixel);
header = std::move(other.header);
width = other.width;
height = other.height;
size = other.size;
bitsPerPixel = other.bitsPerPixel;
return *this;
}
private:
std::vector<RGBA> pixel; //Containes every pixel of the picture
TGAHeader header;
short width, height, size, bitsPerPixel;
...
public:
/**
* Loads and initializes a picture to be used in the program
* #throws TGAExpection if file could not be loaded
*/
static std::unique_ptr<TGAPicture> loadPicture(const std::string& path);
TGAPicture(const std::vector<RGBA>& pixel, const TGAHeader& header);
~TGAPicture();
....
};
}
#endif
cpp:
TGAPicture::TGAPicture(const std::vector<RGBA>& pixel, const TGAHeader& header)
: pixel(pixel),
header(header),
width(header.width),
height(header.height),
size(header.width * header.height * (header.bits / 8)),
bitsPerPixel(header.bits) { }
std::unique_ptr<TGAPicture> TGAPicture::loadPicture(const std::string& path) {
...
for (int i = 0; i < header.height * header.width; i++) {
pixel[i].B = *(bufferPosition++);
pixel[i].G = *(bufferPosition++);
pixel[i].R = *(bufferPosition++);
pixel[i].A = (header.bits > 24 ? *(bufferPosition++) : 0xFF);
}
/**
* Return unique_ptr
* - ObjectFactory
* - Automatic Deletion
*/
return std::unique_ptr<TGAPicture>{new TGAPicture(pixel, header)};
}
And one class with an error would be:
class Model {
public:
explicit Model(const CreatureList& creatureList);
~Model();
Terrain* getTerrain() const;
CreatureList& getCreatureList();
private:
CreatureList creatureList;
Terrain* terrain;
};
Model::Model(const CreatureList& creatureList) : creatureList(creatureList),
terrain(new Terrain()) {
for (CreatureType ty : creatureList) { //line with errror
ty.getInfoInOneLine();
}
}
What do I need to change for it to work? And what would be the optimal way? Pretty sure that I'm supposed to use unique_ptr as return for the TGA::load() method.
I hope you can see through this mess and I'd like to apologize if my English isn't perfect, since it's not my first langugage.
std::unique_ptr is not copyable. It wouldn't be unique anymore if you could copy it.
You create copies of the elements in creatureList in your loop in Model's constructor, but they have a non-copyable member, and so are non-copyable themselves by default. If you don't actually need a copy of the elements, you should use references:
Model::Model(const CreatureList& creatureList)
: creatureList(creatureList),
terrain(new Terrain())
{
for (CreatureType& ty : creatureList) { // changed to reference instead
// Note: this is still working with
// parameter, not the object's
// member.
ty.getInfoInOneLine();
}
}
You haven't actually provided a definition for CreatureList, but I suspect it also isn't copyable. This means that Model::Model's argument can't be copied into the object's member. You have two options to fix this: make sure to move your CreatureList or make it copyable.
std::unique_ptr is movable, which means that CreatureType is by default as well, so you can do something like this:
Model::Model(CreatureList creatureList) // Take by value now
: creatureList(std::move(creatureList)), // Move the parameter to the member
terrain(new Terrain())
{
for (CreatureType& ty : this->creatureList) { // Use this-> to access member
// instead of now moved-from
// parameter. You could also
// just change them to have
// different names.
ty.getInfoInOneLine();
}
}
This changes Model's constructor to take its parameter by value and moves that value into the object's creatureList member.
If it makes sense, you could also make CreatureType copyable by adding an explicit copy constructor that copys the object pointed to by picture:
CreatureType::CreatureType(const CreatureType& other)
: name(other.name),
strengh(other.strengh),
speed(other.speed),
lifespan(other.lifespan),
attributes(other.attributes),
path(other.path),
picture(new TGAPicture(*other.picture))
{
}
If you do that, the implicit move constructor will no longer be generated by the compiler, so you'll want to define that yourself:
CreatureType::CreatureType(CreatureType&& other)
: name(std::move(other.name)),
strengh(other.strengh),
speed(other.speed),
lifespan(other.lifespan),
attributes(std::move(other.attributes)),
path(std::move(other.path)),
picture(std::move(other.picture))
{
}
There doesn't seem to be any reason for TGAPicture::loadPicture to return a std::unique_ptr though. If you just return by value from that function you will avoid all of these problems:
TGAPicture TGAPicture::loadPicture(const std::string& path) {
// ...
return TGAPicture{pixel, header};
}

Initialise const member variables in class using values from file input

I want to define a const variable which is part of a class like:
// camera.h
class Camera{
public:
Camera(std::string file);
~Camera() {}
const size_t FRAME_HEIGHT;
const size_t FRAME_WIDTH;
private:
std::string file;
cv::VideoCapture cap;
Read();
};
_____________________________________
// camera.cpp
Camera::Camera(std::string file) : file("settings.yml") {
//...
read();
cap.open(0);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT);
cap.set(CV_CAP_PROP_FRAME_WIDTH, FRAME_WIDTH);
}
void Camera::read(){
// read something
}
However this does not work using an initialisation list because I first have to read this data from a settings file.
After calling read() I set my const variables FRAME_HEIGHT and FRAME_WIDTH.
Is it possible to leave them const and if yes how/where should I do that?
It is possible if you use an intermediate class, like this:
class Camera {
struct Reader {
int value;
Reader(bool x) {
// Do whatever you like
value = x ? 42 : 0xDEAD;
}
};
Camera(Reader&& r) : value(::std::move(r.value)) { }
public:
int const value;
template<typename... V>
Camera(V... args)
: Camera(Reader(std::forward<V>(args)...))
{ }
};
This effectively adds another stage to the initialization, but still keeps encapsulation (Reader and the corresponding constructor are private to Camera!). The performance impact should be negligible (forward and move operations are usually cheap), unless you initialize millions of these objects in some tight inner loop.
One option is to initialize a settings object from a file, and take needed values from it:
class Camera
{
// note this section is moved to the beginning,
// so file and settings are initialized before FRAME_HEIGHT and FRAME_WIDTH
private:
std::string file;
Settings settings;
public:
Camera(std::string file)
: file(file)
, settings(file)
, FRAME_HEIGHT(settings.getFrameHeight())
, FRAME_WIDTH(settings.getFrameWidth())
{
}
~Camera() {}
const size_t FRAME_HEIGHT;
const size_t FRAME_WIDTH;
};
Also it could make sense to rewrite Camera constructor after that as
Camera(const Settings& settings)
: FRAME_HEIGHT(settings.getFrameHeight())
, FRAME_WIDTH(settings.getFrameWidth())
{
}
-- this way you can take settings from anywhere, not only from a file.

Accessor issues in c++

This is my code.When I'm trying to print the value from getter, it is giving me some special characters but not the value I actually set.
class Car{
public:
Car(char* manufacturer,char* modelName,int mfgYear,char* color,double cost,int mpg){
strcpy(mfg,manufacturer);
strcpy(this->color,color);
strcpy(this->modelName,modelName);
this->MfgYear=mfgYear;
this->vehicleCost=cost;
this->mpg=mpg;
};
char* getManufacturer();
void setManufacturer(char* x);
};
char* Car::getManufacturer(){
return this->mfg;
}
void Car::setManufacturer(char* mfgName)
{
strcpy(this->mfg,mfgName);
}
int main(){
Car().setManufacturer("asds");
cout<<Car().getManufacturer();
}
You are creating an object of type Car on the stack, but you are not saving any reference to it. When you call Car().setManufacturer("asds"), it will create an object of type Car on the stack, but if you do not save a reference to it, you will technically lose it. What you want to do is assign it to something. Here is what you can do:
Car myCar;
myCar.setManufacturer("asds");
cout << myCar.getManufacturer();
There are a few problems with your code, currently:
1. You're not initializing a Car object in your main method - there is no object to call these methods upon. This can be fixed by modifying your main method:
int main() {
Car c("Manufacturer", "Model", 2000, "Color", 9999.99, 20);
c.setManufacturer("asds");
cout << c.getManufacturer() << endl;
}
2. You are trying to copy data to objects that aren't initialized inside the class (MfgYear, vehicleCost, mpg, color, modelName, mfg).
private:
int MfgYear;
double vehicleCost;
int mpg;
char color[80];
char modelName[80];
char mfg[80];
I have included the corrected class below:
class CarChar
{
private:
int MfgYear;
double vehicleCost;
int mpg;
char color[80];
char modelName[80];
char mfg[80];
public:
Car(char* manufacturer, char* modelName, int mfgYear, char* color, double cost, int mpg)
{
// Copy the data to the objects
strncpy(this->mfg, manufacturer, sizeof(this->mfg));
strncpy(this->color, color, sizeof(this->color));
strncpy(this->modelName, modelName, sizeof(this->modelName));
this->MfgYear = mfgYear;
this->vehicleCost = cost;
this->mpg = mpg;
}
char* getManufacturer() {
return this->mfg;
}
void setManufacturer(char* mfgName) {
strncpy(this->mfg, mfgName, sizeof(this->mfg));
}
};
Note: If you notice in the above class, I replaced all calls to strcpy to strncpy to reduce the chance of buffer overflow, a security problem.