Should you have a getter function for class array? - c++

I'm learning C++, and have a question related to classes and templates.
I know it's good practice to have "getters" for every variable in your class and a "setter" function. But with the code shown below, should you have a "getter" function for the array? In theory, the print function would serve the same purpose as the "getter" function would - print out everything in the array. If it is required, what would the correct code be to return that array? The array is an array of class objects.
My thinking and the code thus far:
queue.h
#pragma once
template<class T>
class Queue {
public:
Queue(int = 1);
~Queue();
void setQueue(int);
void enqueue(T);
void dequeue();
const T* getQueueArray() const;
const int getArraySize() const;
const int getArrayIndex() const;
void printQueue();
private:
T* queueArray;
int arraySize, arrayIndex;
};
queue.cpp
#include <iostream>
#include "queue.h"
template<class T>
Queue<T>::Queue(int arraySize) {
this->setQueue(arraySize);
}
template<class T>
Queue<T>::~Queue() {
delete [] this->queueArray;
}
template<class T>
void Queue<T>::setQueue(int arraySize) {
this->arraySize = arraySize;
delete [] this->queueArray;
this->queueArray = new T[arraySize];
this->arrayIndex = 0;
}
template<class T>
void Queue<T>::enqueue(T object) {
if (this->arrayIndex == this->arraySize) {
std::cout << "Rinda ir pilna, nevar pievienot elementu!\n";
}
else {
this->queueArray[this->arrayIndex] = object;
this->arrayIndex++;
}
}
template<class T>
void Queue<T>::dequeue() {
if (this->arrayIndex == 0) {
std::cout << "Rinda ir tuksa!\n";
}
else {
for (int i = 0; i < this->arraySize - 1; i++) {
this->queueArray[i] = this->queueArray[i + 1];
}
this->arrayIndex--;
}
}
template<class T>
const T* Queue<T>::getQueueArray() const {
return this->queueArray;
}
template<class T>
const int Queue<T>::getArraySize() const {
return this->arraySize;
}
template<class T>
const int Queue<T>::getArrayIndex() const {
return this->arrayIndex;
}
template<class T>
void Queue<T>::printQueue() {
for (int i = 0; i < this->arrayIndex; i++) {
std::cout << i + 1 << ". ";
this->queueArray[i].printHuman();
}
}
The array getter function works and returns a memory address. Is that behavior correct?
And I'd like to ask another question, for class print functions, which would be the better of the 2:
std::cout << "something something" << classVariable;
or
std::cout << "something something" << getClassVariable();
One way is accessing the variables directly and the other is using the "getter" functions. Does it matter and does using functions like that impact performance in a noticable way?

This post is largely opinion-based, but I'm going to offer my perspective. You've received comments telling you a few things.
First, I'd encourage you to do things "the C++ way". Templates are done in the header, and it's really gross to "#include "queue.cpp". But I understand at least for an example that's maybe okay, as it lets you focus on other things than all the code to implement the entire template. Just don't do it in practice.
As for getters and setters -- I disagree with some of the comments you're getting. I absolutely would NOT put a setter on the internal structure, but if this is a serious class, I'd absolutely implement some way to inspect the full contents.
Imagine, after all, that someone wants to be able to count how many elements in the queue have fulfill a particular constraint. You don't want to try to anticipate evreything someone might want to do. But you can certainly put some means of inspecting the contents, either by being able to get the current queue (const) or via iterators. Iterators are harder to implement, but they fit a lot of other algorithms. See the entire contents of #include .
So:
Yes on some sort of access system (a getter / iterator)
No on a setter
In addition to this, I'm not sure why your sample code isn't willing to grow the list if necessary, but if it's not going to, it should somehow indicate to the caller that it failed to enqueue properly.

First of all for templated classes, having the declaration in a header file and having the definitions on a source file wont work. So try putting them in the same header file.
I know it's good practice to have "getters" for every variable in your class and a "setter" function
Yes that is true but not always. Getting the actual data pointer will help for example when copying data to a buffer. Setting is usually done by assignment operators,
Value& operator=(const Object& other) { ... } // Copy assign operator.
Value& operator=(Object&& other) { ... } // Move assign operator.
So I would advice not to have a setter in these type of objects.
And I'd like to ask another question, for class print functions, which would be the better of the 2:
std::cout << "something something" << classVariable; or std::cout << "something something" << getClassVariable();
This is opinion based and usually you print the content to the console by overloading the << operator,
template<class T>
ostream& operator<<(ostream& os, const Queue<T>& dt)
{
os << /* print content */;
return os;
}
int main()
{
Queue<int> queue;
std::cout << "Printing queue! " << queue;
}
One way is accessing the variables directly and the other is using the "getter" functions. Does it matter and does using functions like that impact performance in a noticable way
Nope they wont. If you inline the functions, there wont be no performance differences. And make sure you enable optimizations or else additional debug information would slow it down. I would argue that using a getter function would be safer.

Related

Creating an Array of pointers to member functions

In short, I tried searching on how to do this, but I seem to be missing something. One constraint to my problem: Human.h cannot change. We must operate with what we've been given. I am also told to create the array of pointers to members to decide on which function needs to be called.
Here's what I have:
Human.h
class Human
{
private:
void meleeAttack(std::string const& target);
void rangedAttack(std::string const& target);
void intimidatingShout(std::string const& target);
public:
void action(std::string const& action_name, std::string const& target);
};
Human.cpp
#include "Human.h"
typedef void (Human::* Human_mem_fnPtr)(std::string target);
void Human::meleeAttack(std::string const& target)
{
std::cout << "Melee Attack performed on " << target << "!\n";
}
void Human::rangedAttack(std::string const& target)
{
std::cout << "Ranged Attack performed on " << target << "!\n";
}
void Human::intimidatingShout(std::string const& target)
{
std::cout << "Shout performed on " << target << "!\n";
}
void Human::action(std::string const& action_name, std::string const& target)
{
//error on initialization--expression must be an lvalue or function designation--but they ARE func designations...
Human_mem_fnPtr fnPtr[] = {&Human::meleeAttack(target), &Human::rangedAttack(target), &Human::intimidatingShout(target)};
}
From what I found online, I am going in the right direction here. What am I missing?
A couple of points:
Doing pointers to functions is made much easier with the std::function<> template class.
Using a old-style array is not really the best choice these days.
A map or unordered_map would be a much better option, with a definition like this:
using ActionMap = std::unordered_map<const std::string, std::function<void(const std::string&)>;
When adding your functions to this map you would use something like the following:
mActionMap["rangedAttack"] = std::mem_fn(&Human::rangedAttack);
This will give you a cleaner and easier to maintain option and should compile cleanly.
Note that the std::mem_fn is required to wrap a member function of a class.
Edit: Per your comment below, Id still suggest using as many of the modern C++ constructs as possible.
using ActionFunc = std::function<void(const std::string&)>;
And then:
ActionFunc actions[] = { std::mem_fn(&Human::rangedAttack), ...}
or:
std::array<ActionFunc> actions = ...

How to create a "factory function" for a templated class?

How would someone go about implementing a factory function for a templated class? Either my google searches aren't looking for the right thing, or I am misunderstanding the results. As an example:
template<typename T>
class Test
{
public:
T data;
void SizeOfData() { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};
----this what I am trying to figure out how to do------
template <typename T>
Test<T> FactoryFunction(const std::string& type)
{
if(type == "int")
return Test<int>;
if(type == "long")
return Test<long long>;
}
----------------------------------------
int main()
{
auto a = FactoryFunction(std::string("int"));
auto b = FactoryFunction(std::string("long"));
a.SizeOfData();
b.SizeOfData();
a.data = 1;
b.data = 2;
}
Obviously, this code is all wrong - I am just trying to show what I want to do in theory. Can it be done? What do I look up in google - Factory functions to return templated classes? I am not even sure where to start. If someone could even point me in a direction - I really just want a function the returns the correct template instantiation based on the results of a switch or if/else list. I think conceptually the idea isn't hard, but implementing it is another thing - or I am really missing something.
Thanks for any help.
The type T of a templated function has to be determined in compile time.
Therefore you cannot do it the way you mentioned.
However - you can use the following pattern to achieve a similar result:
#include <assert.h>
class TestBase
{
public:
virtual void SizeOfData() = 0;
};
template<typename T>
class Test : public TestBase
{
public:
T data;
virtual void SizeOfData() override { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};
std::unique_ptr<TestBase> FactoryFunction(const std::string& type)
{
if (type == "int")
return std::make_unique<Test<int>>();
if (type == "long")
return std::make_unique<Test<long long>>();
return nullptr;
}
int main()
{
auto a = FactoryFunction(std::string("int"));
assert(a);
auto b = FactoryFunction(std::string("long"));
assert(b);
a->SizeOfData();
b->SizeOfData();
return 0;
}
Some notes:
Each instance of Test (where T changes) is a differnt an unrelated class. In order to create a connection between them, I added a common base class.
In order to use polymorphism, you must use refernce semantics. Therefore the factory returns a pointer (in this case a std::unique_ptr).
The common method you need to invoke on all your Test objects (SizeOfData) became a virtual method in the base class.
This technique is actually related to the idiom of type erasure mentioned in the comments.
UPDATE: based on the comment below, I replaced using naked news with std::make_unique.
You can see more info why it is better here: Differences between std::make_unique and std::unique_ptr with new

How to use a compile-time interface with a runtime type?

I have a function that takes a T and calls specific functions on the supplied object. Until now it was used from compile-time objects, so all was great. Minimal example:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
Now I'm trying to use that use_function() with objects that get created at runtime and having a hard time. I can't use std::variant or std::any since I need to supply the type as template parameter for their access functions - although all their variants fulfil the function interface. Example for a (failing) variant approach:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
What is possible is directly calling the function with an appropriate type like this:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
just storing it in between is what I can't get working.
I understand on a technical level but having trouble coming up with an elegant solution. Is there one? I know that I could rewrite the objects with even a lightweight inheritance - but was trying to see if it's feasible to avoid it altogether, even if just as an exercise to avoid OOP in favor of templates and concepts. I feel like variants should be working with this, but apparently not.
std::visit([](auto const& x) { use_function(x); }, var);
If overload sets were objects, you could pass use_function to std::visit directly. Because they aren't, you need to wrap it in something that will be instantiated as a call to the right overload.
std::visit([](auto const& x) { use_function(x); }, var);

How can I perform perfect forwarding without using templates?

I want perfect forwarding but I already know (and only accept) the type my function will take.
Here is a quick example I typed up:
class big_class
{
private:
std::string m_somethingBig;
};
class testmove
{
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
m_bigClasses.push_back(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
m_bigClasses.push_back(big);
}
private:
std::vector<big_class> m_bigClasses;
};
int main()
{
testmove tm;
big_class big;
tm.Add(big);
tm.Add(big_class{});
}
Live Sample
Is it possible to do some form of implementation sharing between the two overloads of testmove::Add()? I want to optimize for move, and if someone does std::move() without my rvalue overload it will end up doing at least 1 copy before it is added to my vector.
Again, I realize I can solve this problem by making Add() a template function, and even using type traits and some template trickery. But I wanted to avoid this if possible. If you need to know why, I have a few reasons:
I can't do implementation hiding with a template (restrict includes and symbol visibility to a single translation unit)
Using a template here gives me more flexibility than I want (My contract requires I only use a big_class).
Using a template would impact readability/maintainability for what should be a simple interface.
The approach suggested by Xeo (take the parameter by value) is the one I would strongly recommend. However, if for some reason you can't do that (e.g., moves are expensive but less so than copies), keep reading.
I think it's possible to satisfy all your criteria, but it's only worth it if the code is complicated enough so that duplicating it would be bad. The idea is to delegate to a template that will be explicitly instantiated only for big_class.
big_class.h:
// ...
public:
void Add(big_class&& big)
{
Add_internal(std::move(big));
}
void Add(big_class const& big)
{
Add_internal(big);
}
private:
// not part of interface; defined in .cpp file
template <typename T> void Add_internal(T&& big);
big_class.cpp:
// implementation of template
template <typename T> void big_class::Add_internal(T&& big) {
// shared logic goes here
m_bigClasses.push_back(std::forward<T>(big));
}
// explicit instantiation
template void big_class::Add_internal<big_class>(big_class&&);
template void big_class::Add_internal<big_class const&>(big_class const&);
if you really can't stand the idea of adding by value, you may provide one internal templated impl:
private:
template<class X>
auto add_impl(X&& x) {
m_bigClasses.push_back(std::forward<X>(x));
}
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
add_impl(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
add_impl(std::move(big));
}
How can this work? you're moving a const ref!
Because std::move does not move anything. It merely casts an l-value reference to an r-value reference. So const T& becomes a const T&&, which no-one ever codes for. So it will decay to match the const T& or T that people do code for.

C++, memory and arrays. Creating my own hashmap for exercise. Unexpected data left in memory?

So i'm trying to create a pretty specific for my needs hashmap for a small project where i'm trying to learn c++. I have the following code:
template<class T>
class HashMap
{
public:
HashMap();
virtual ~HashMap();
void add(T value);
T get(T *value);
private:
int hash(T *data);
T _hashes[26]; //I want a fixed size here
};
template<class T>
HashMap<T>::HashMap()
{
for(int i = 0; i < 26; i++)
this->_hashes[i] = T();
}
template<class T>
HashMap<T>::~HashMap()
{
//Don't really have anything to delete here?
}
template<class T>
int HashMap<T>::hash(T *dat)
{
//Super simple, just to try things out
return (long int) dat % 26;
}
template<class T>
T HashMap<T>::get(T *val)
{
int idx = this->hash(val);
cout << idx << endl;
//Probably somewhere here i get my problem
if(this->_hashes[idx])
return this->_hashes[idx];
return T();
}
template<class T>
void HashMap<T>::add(T val)
{
//Should probably do some check if there's already an element here.
this->_hashes[this->hash(&val)] = val;
}
The problem im having is that this compiles fine but when I do something like this in my main.cpp:
HashMap<char> a = HashMap<char>();
a.add('h');
a.add('c');
a.add('g');
char *b = new char {'c'};
cout << a.get(b) << endl;
delete b;
It usually returns the id, ie:
4
and an empty line which is just a empty char. (the output of the function is in the get() method), but sometimes it will show me something like this:
18
g
instead of 18 and an empty line. My question is why this happens and how i can prevent it? Does it have something to do with memory not being 'nulled' when it's deleted but just free for other programs to take and then i don't initialise it correctly?
Also, if you have the time please point out any mistakes or not so good to do things in the code.
If it's of any interest im using GCC Debian 4.4.5-8 to compile and compile it with g++ -g file.cpp -o file
Thankful for any help!
The behavior you see is normal: if you get a value that you put in your hash, it will be displayed by your main. What is giving you surprising results is your hash function:
return (long int) dat % 26;
This hashes the dat pointer, not the T that dat points to. Try with:
return *dat % 26;
(Or just use a standard std::set.)
Another problem with your code:
T _hashes[26]; //I want a fixed size here (a
and
this->_hashes = new T[26]; (b
are incompatible. Either use the fixed array (a) and you don't need to allocate it (b), or use a plain pointer (T *_hashes) and do (b) - I'm surprised your compiler accepts what you have. If you use (a) you don't need anything in the destructor. If you use (b), you need to delete [] in your destructor.
Passing a T* in get but a T in set is a bit strange too.
Here's a more idiomatic c++ implementation:
#include <array>
#include <iostream>
#define MAGIC_NUMBER 26 //rename this to something else preferably
template<class T>
class HashMap
{
public:
HashMap();
virtual ~HashMap(){};
void add(T value);
T get(T *value);//potentially confusing that add and get take different types
private:
int hash(T *data);
std::array<T, MAGIC_NUMBER> _hashes; //I want a fixed size here
};
template<class T>
HashMap<T>::HashMap()
{
std::fill(_hashes.begin(),_hashes.end(), T());
}
template<class T>
int HashMap<T>::hash(T *dat)
{
//Super simple, just to try things out
return (static_cast<int>(*dat)) % MAGIC_NUMBER;//prefer using c++ casts
}
template<class T>
T HashMap<T>::get(T *val) //this is strange, you pass in a pointer and get a non-pointer
{
int idx = this->hash(val);
std::cout << idx << std::endl;
if(this->_hashes[idx])
return this->_hashes[idx];
return T();
}
template<class T>
void HashMap<T>::add(T val)
{
//Should probably do some check if there's already an element here.
this->_hashes[this->hash(&val)] = val;
}
int main(void){
HashMap<char> a = HashMap<char>();
a.add('h');
a.add('c');
a.add('g');
char *b = new char {'c'};
std::cout << a.get(b) << std::endl;
delete b;
}
Note you will need to compile with c++0x or c++11 features to get the usage of the std::array class. One of the main benefits of the array class is that you get more safety with the memory allocation than just a plain c-style array.
Right now you might want to reconsider some elements of the design. In particular it is confusing that add and get, have different types. Also this isn't what people generally think about when they hear hashmap, this structure is more like a set.
Also as a coding standards note, if you are prefixing your member variables it's a bit tautological to also use this-> to access them.