I am still relatively new to C++, learning as I go, and I'm confused as to what is the 'best' way to expose the vector to its consumers. I'm not worried about performance.
I have a class that contains a vector of raw data. I have other classes that need to consume and process that vector.
From reading other posts here I'm not sure whether to return a const reference to the vector or expose const iterators as none of the consumers will modify the vector.
Is one way better than the other? Are there other options or other things to consider ?
typedef std::vector<int> RawNumberContainer;
typedef std::vector<int>::const_iterator RawNumberIterator;
class RawData
{
public:
RawData();
void addNumber(int number)
{
rawNumbers.push_back(number);
}
// this?
RawNumberContainer getRawNumbers() { return rawNumbers; }
// or this?
const RawNumberContainer& getRawNumbersConstReference() { return rawNumbers; }
// or this?
RawNumberIterator getRawNumbersBeginning() { return rawNumbers.begin(); }
RawNumberIterator getRawNumbersEnd() { return rawNumbers.begin(); }
private:
RawNumberContainer rawNumbers;
};
class Something;
class RawDataConsumer
{
public:
// ??
Something* processRawData(RawNumberContainer&);
// ??
Something* processRawData(const RawNumberContainer&);
// ??
Something* processRawData(RawNumberIterator begin, RawNumberIterator end);
};
It:
const RawNumberContainer& getRawNumbersConstReference() const { return rawNumbers; }
And it:
Something* processRawData(const RawNumberContainer&);
You can use:
RawNumberContainer getRawNumbers() const { return rawNumbers; }
This way you'll make sure you can't edit the vector (only read-only access) and spare you of another variable being manually declared in your code.
Related
I have some doubts about optimization regarding storing elements in vectors and getting information from them. Lets see the example
struct Entity
{
public:
Entity() = default;
bool isActive = false;
std::vector<SomeOtherClass> classesThatUseEntity;
}
class Manager
{
public:
Manager() = default;
const std::vector<Entity>& GetOnlyActiveEntity()
{
std::vector<Entity> value;
for (const auto& entity : differentSettings)
{
if (entity.isActive)
{
value.emplace_back();
}
}
return value;
}
private:
std::vector<Entity> differentSettings;
}
I was thinking of maybe using a vector of pointers to return values:
std::vector< boost::intrusive_ptr<Entity>> GetOnlyActiveEntity()
with this, I got some comments from colleagues that the vector of pointers, in this case, is not the smart option because of heap fragmentation, but I am not sure that this comment is legit. What do you think?
Apologies if this is a trivial problem.
I'm trying to pass a multimap that has been put together with one class in a library to another class in that library in order to further manipulate the data there.
The code relates to a GUI written by other people and the classes here relate to two different tools in the GUI.
Very roughly speaking my code and what I'm after here is like this
class A
{
private:
std::multimap<int, double> mMap;
int anInt;
double aDouble;
***some more definitions***
public:
void aFunction(***openscenegraph node, a string, and a parser function***)
{
***a few definitions are declared and initialised here
during calculations***
***some code calculating data stuff that
passes bits of that data to mMap (including information
initialised within the function)***
}
}
class B
{
public:
void bFunction(***openscenegraph node and some other data***)
{
***I want to be able to access all the data in mMap here***
}
}
Can anyone make it clear to me how I can do this, please?
Edit: Added to clarify what i'm aiming for
//Edit by Monkone
//section below is akin to what I'm trying to do
class B
{
private:
std::multimap<int, double> mMapb;
public:
std::multimap<int,double> bFunction2(A::MultiMapDataType data)
{
return mMap;
}
void bFunctionOriginal()
{
***I want to be able to access all the data in mMap here***
***i.e. mMapb.bFunction2(mMap);***
***do stuff with mMapb***
}
}
However I can't get anything to actually do something like this
I won't be needing to work on the map, only get information from it.
You could then add a function to return a const reference to the map and functions for returning const iterators to A:
class A {
public:
typedef std::multimap<int, double> intdoublemap_t;
typedef intdoublemap_t::const_iterator const_iterator;
// typedef intdoublemap_t::iterator iterator;
private:
intdoublemap_t mMap;
public:
// direct access to the whole map
const intdoublemap_t& getMap() const { return mMap; }
// iterators
const_iterator cbegin() const { return mMap.begin(); }
const_iterator cend() const { return mMap.end(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
/*
iterator begin() { return mMap.begin(); }
iterator end() { return mMap.end(); }
*/
};
Now you can iterate over the map from the outside (from B):
void bFunction(const A& a) {
for(A::const_iterator it = a.begin(); it!=a.end(); ++it) {
std::cout << it->first << " " << it->second << "\n";
}
}
Or access the map directly:
void bFunction(const A& a) {
const A::intdoublemap_t& mref = a.getMap();
//...
}
The C++ private members cannot be accessed by other (non friend) classed.
The first solution it would be to keep mMap private (not polite to work on other classes members) and offer assessors over it.
class A
{
public:
typedef std::multimap<int, double> MultiMapDataType;
private:
MultiMapDataType mMap;
***some more definitions***
public:
const MultiMapDataType& getConstMMap() const;
MultiMapDataType getMMap();
}
class B
{
public:
void bFunction(A::MultiMapDataType data)
{
***I want to be able to access all the data in mMap here***
}
void bFunction2(const A::MultiMapDataType& data)
{
***I want to be able to access all the data in mMap here***
}
}
A a;
B b;
b.bFunction(a.getMMap());
b.bFunction2(a.getConstMMap());
However, from architectural point, if you have multiple members that you need to share you should move them all in a new structure/class that encapsulates that functionality.
I have class called "UltrasoundTemplate". These UltrasoundTemplate objects contain an int parameter, which shows when they where defined (something like a time stamp). And I have a class called "UltrasoundTarget" which contains a vector of UltrasoundTemplate's.
I add UltrasoundTemplates to the vector with push_back(ultrasoundTemplate).
Now I want to sort the vector by the order of time stamps instead of the order I added them to the vector.
I found a lot of answers in google, which all show me the same solution, but obviously I'm still doing something wrong. Here are the code snippets I think are necessary for finding a solution:
ultrasoundTemplate.h
class UltrasoundTemplate
{
public:
UltrasoundTemplate(/*...*/);
int getVolumePos() { return volume_; }
private:
int volume_;
};
ultrasoundTarget.h
//the sort algorithm
struct MyTemplateSort {
bool operator() ( UltrasoundTemplate t1, UltrasoundTemplate t2){
int it1 = t1.getVolumePos();
int it2 = t2.getVolumePos();
if (it1 < it2)
return true;
return false;
}
};
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
FMainWindow.cpp
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName) {
//here I try to sort
MyTemplateSort tmpltSrt;
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
break;
}
}
As an example: I define Template1 in Volume(0), Template2 in Volume(70) and Template3 in Volume(40). The order now is (Template1, Template2, Template3) but I want it to be (Template1, Template3, Template2). But this code is not doing it.
If there's Information missing, just tell me and I'll provide more code.
Thanks alot.
Your getTemplates() method returns by value, making a mess here:
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
You are sorting an incompatible iterator range. You can fix that particular problem by returning a reference:
vector<UltrasoundTemplate>& getTemplates() { return USTemplateVector_; }
It is common practice to add a const overload to such a method:
const vector<UltrasoundTemplate>& getTemplates() const { return USTemplateVector_; }
You can also modify your comparison functor to avoid unnecessary copies (and for general readability and const correctness):
struct MyTemplateSort {
bool operator() const ( const UltrasoundTemplate& t1, const UltrasoundTemplate& t2)
{
return t1.getVolumePos() < t2.getVolumePos();
}
};
This will require that you make getVolumePos() a const method, which it should be anyway:
class UltrasoundTemplate
{
public:
...
int getVolumePos() const { return volume_; }
...
};
Note that is is not generally good practice to provide references to the private data of a class. If possible, you should find a way to remove that from the UltraSoundTarget interface. You could, for instance, expose a pair of iterators, and/or give the class a sort method.
juanchopanza answer is correct, the problem is the way you are returning the vector from UltrasoundTarget. Just to touch another topic, maybe it would be nice to change a little the designing of your implementation. As UltrasoundTarget is a container of Ultrasound's, it makes sense to implement the sort as a method of this class, this way you have direct access to USTemplateVector_ and will save unecessary copies. Something like:
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
void sort();
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
void UltrasoundTarget::sort()
{
std::sort(USTemplateVector_.begin(), USTemplateVector_.end(), tmpltSrt);
}
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName)
{
//here I try to sort
MyTemplateSort tmpltSrt;
USTargetVector.at(i).sort();
break;
}
}
Here's my problem,
Class MClass {
public:
void Add(OtherClass* objects) {
_objects = objects;
}
private:
OtherClass* _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
OtherClass obj[NUMBER_OF_OBJECTS];
//obj initialization here
//...
myObj.Add(obj);
}
It will cause a RT error because the *obj diminishes after the end of the function body.
But, how can make this one valid?
I like to initialized first an object before assigning it to other class.
EDIT
I don't want to use storage classes or something here, I just want a raw array since it is very expensive for me to use. Its functionality will not lessen my problem here.
So how do I do that in a raw-array style?
Class MClass {
public:
void Add(std::vector<OtherClass> objects) {
_objects = std::move(objects);
}
private:
std::vector<OtherClass> _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
myObj.Add(std::move(obj));
}
In your example, you store a pointer to a local array. If the method ends, the array goes out of scope and doesn't exist anymore.
This is the reason, your pointer is not valid anymore. If you want to solve this, learn about the scope of variables in C++.
It is not completely clear what you are trying to do, but you could store a collection of objects instead of a pointer:
class MClass
{
public:
void Add(const std::vector<OtherClass>& objects) {
objects_ = objects;
}
void Add(std::vector<OtherClass>&& objects) {
objects_ = std::move(objects);
}
private:
std::vector<OtherClass> objects_;
};
then
void Setup()
{
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
//obj initialization here
//...
myObj.Add(std::move(obj)); // move obj's contents onto myObs's objects.
}
Stop using raw arrays, and use either std::vector or std::array. Then you don't have to worry about it anymore.
If you really want to do it manually, you have to copy is manually as well. Using e.g. std::vector and std::move is more effective, but here you go:
Class MClass {
public:
MClass()
: _objects(nullptr), _count(0)
{}
MClass(const MClass& other)
: _objects(nullptr), _count(0)
{
Add(other._objects, other._count);
}
~MClass()
{
if (_objects != nullptr)
delete [] _objects;
}
void Add(const OtherClass* objects, const size_t count)
{
if (_objects != nullptr)
delete [] _objects;
_objects = new [count];
for (size_t i = 0; i < count; i++)
_objects[i] = objects[i];
_count = count;
}
MClass& operator=(const MClass& other)
{
Add(other._objects, other._count);
}
private:
OtherClass* _objects;
size_t _count;
};
// ...
myObj.Add(obj, NUMBER_OF_OBJECTS);
As you can see, it's a lot of more code, which makes it harder to follow and debug, and also larger possibility of errors. And not as "effective" as I said above.
Say I have a class with a couple of data members, and I want a class method that returns one, and the next time it is called returns the value of the other. Something like:
class MyClass
{
public:
MyClass():switch(0){};
int get();
private:
int intA, intB;
int sw;
};
int MyClass::get()
{
if ( (++sw)%2 )
return intA;
else
return intB;
}
What would a more elegant way of doing it be? I don't like the if...else statement very much. It's fine for something like return, but if I'm actually using more complex operations, I end up duplicating a ton of code. Or having to create a second method within each method that is called after I resolve what element I'm pointing to.
What I'd prefer to do, ideally, is to use some form of pointer, so I can do
class MyClass
{
public:
MyClass():switch(&intA){};
int get();
void toggleSwitch();
private:
int intA, intB;
int * sw;
};
int MyClass::get()
{
return *sw;
}
void MyClass::toggleSwitch()
{
if ( sw == &intA )
sw = &intB;
else
sw = &intA;
}
Or something to that effect. I could call toggleSwitch(), and have my class operate on either one or the other value easily.
I still don't like it though. I prefer to avoid if's when possible, and I shouldn't need one in this case. This use of a naked pointer should be pretty safe, but I was thinking I could have something like std::unique_ptr holding each element and then std::swap them. But then the pointers would own the elements, and they'd be dynamic memory instead.
So is there a better way to do it?
Well, switch is a keyword, but I'll roll with it. How about an array of pointers?
int *fields[] = {&intA, &intB};
int MyClass::get()
{
return *fields[++switch % 2];
}
This would expand nicely if you could have additional variables later.
Or maybe:
int MyClass::get()
{
return *fields[switch = 1 - switch];
}
If you return a reference then you could use get() internally.
int &MyClass::get()
{
return *fields[switch = 1 - switch];
}
I would encapsulate the concept of a toggling value:
template<typename T>
class Toggleable {
T first;
T second;
T* current;
T* other;
public:
Toggleable(const T& first, const T& second)
: first(first),
second(second),
current(&first),
other(&second) {
}
bool toggle() {
std::swap(current, other);
}
const T& get() const {
return *current;
}
}
Then use as:
class MyClass
{
Toggleable<int> value;
public:
MyClass()
: value(42, 1729)
{
}
const int& get() {
value.toggle();
return value.get();
}
};