I have some function where I need to use a member variable(a vector of custom classes).
At the end of this function this member needs to be cleared but it needs to stay as a member for the duration of this function.
Another problem is that the function can end prematurely due to custom error handling of the program. Yet the member still needs to be cleared.
I first moved this member at the beginning in a local variable using std::move.
This worked pretty well but it now turns out I need the variable to stay as a member variable till the end of that function.
I came up with the following solution using a unique_ptr with a reference that will do the move upon destruction.
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
template <class T>
class Clean
{
public:
Clean(T& clean)
: m_clean(clean) {}
~Clean()
{
T destroy = move(m_clean);
}
private:
T& m_clean;
};
class A
{
public:
A()
{
m_numbers = { { 3, 1 ,4, 1, 5} };
}
void display()
{
auto cleanNumbers = make_unique<Clean<vector<int> > >(m_numbers);
for(int number: m_numbers)
cout << number << endl;
}
private:
vector<int> m_numbers;
};
int main()
{
A a;
a.display();
cout << "should be empty now" << endl;
a.display();
return 0;
}
Any cleaner solutions are also welcome but my actual question is the following.
Is there any std equivalent of the Clean class I used?
Ps: code fragment compiles for me using g++ 5.3.0
g++ -std=c++14 -o main main.cpp
This is the result I came to thanks to comments and other questions:
void display()
{
auto cleanNumber = [](decltype(m_numbers)* numbers){
if(numbers)
numbers->clear();
};
auto pClean = std::unique_ptr<decltype(m_numbers), decltype(cleanNumber)>(&m_numbers, cleanNumber);
for(int number: m_numbers)
cout << number << endl;
}
You could use a shared_ptr's custom deleter to obtain the same result.
void A::display()
{
std::shared_ptr<int> dummy (
(int*)alloca(sizeof(int)), // very fast allocate on stack
[&](int*) { this->m_numbers.clear(); }
);
for(int number: m_numbers)
cout << number << endl;
}
Here is the entire code, compiles fine, gcc 5.3 -Wall -Wpedantic -march=native -std=c++14
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class A
{
public:
A()
{
m_numbers = { { 3, 1 ,4, 1, 5} };
}
void display()
{
std::shared_ptr<int> dummy (
(int*)alloca(sizeof(int)),
[&](int*) { this->m_numbers.clear(); }
);
for(int number: m_numbers)
cout << number << endl;
}
private:
vector<int> m_numbers;
};
int main()
{
A a;
a.display();
cout << "should be empty now" << endl;
a.display();
return 0;
}
Related
#include <iostream>
#include <string.h>
#include "Date.h"
#include "Employee.h"
using std::cout;
using std::endl;
using std::to_string;
class TestOps {
public:
int sex = 1;
string toString() {
return " sex:" + to_string(sex) ;
}
};
class Test {
public:
TestOps* testOps;
Test(const Test& t) :Test{} {
this->testOps = new TestOps{ *(t.testOps) };
};
Test() {
TestOps ops;
//this->testOps = new TestOps{}; // it will be ok with this way
this->testOps = &ops;
}
};
int main() {
// code not understand
Test t1;
cout <<"first testOps:" << t1.testOps->toString() << endl; // sex: 1
Test t2{ t1 };
cout << "first testOps:" << t1.testOps->toString() << endl; // sex: -858893460 ???? why?
cout << "second testOps:" << t2.testOps->toString() << endl; // sex: -858893460 ???? why?
return 0;
}
As you can see, why the first log is as expected while the later logs are not?
Also, t1.testOps address is different from t2.testOps which is as expected.
I have done some research but didn't find the answer. Maybe because I'm pretty new to cpp.
So, I have a member function (show_players_names and show_players_levels) of a class which prints on the screen the value of a private variable.
Although the compiler doesn't show any error, I do not see the names and the levels on the screen.
Do you have any idea?
Here's the code:
#include <iostream>
#include <vector>
#include <array>
#include <string>
using namespace std;
class Party {
private:
string boss;
vector<string> players;
vector<int> players_level;
public:
string party_name;
Party (string party_name, string boss) { cout << party_name << " " << boss << endl; };
~Party() { cout << "Party delete" << endl; };
vector<string> getNames() { return players; };
vector<int> getLevels() { return players_level; };
vector<string> setNames (const vector<string> &new_players) { players=new_players; }
vector<int> setLevels (const vector<int> &new_players_level) { players_level=new_players_level;
};
void show_players_names()
{
for(size_t i=0; i<players.size(); i++ )
cout << players[i] << ' ';
cout << endl;
};
void show_players_levels()
{
for(size_t i=0; i<players_level.size(); ++i )
cout << players_level[i] <<' ';
cout << endl;
};
};
int main ()
{
Party party1("Witchers","Vesemir");
party1.setNames({"Gerald","Eskel","Lambert"});
party1.setLevels( {50,45,49} );
party1.show_players_names();
party1.show_players_levels();
return 0;
}
The code
vector<string> setNames (const vector<string> &new_players) {
players=new_players;
}
vector<int> setLevels (const vector<int> &new_players_level) {
players_level=new_players_level;
}
is wrong as there's no return statement.
Changing the declaration of the methods to void makes the code working as expected.
void setNames (const vector<string> &new_players) {
players=new_players;
}
void setLevels (const vector<int> &new_players_level) {
players_level=new_players_level;
}
For reasons not entirely clear to me omitting a return statement in a non-void function on many compilers is not a fatal compile error (what I think it should be) and is instead just a warning, but the generated code has undefined behavior (with g++ for example your code segfaults).
When you execute code containing UB anything can happen, including working apparently but with strange behavior.
I have some troubles with an application that I made. std::move destroys your object when you move it to vector pushback. Here a small example:
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class FileSetting
{
private:
FileSetting(FileSetting &fileSetting) { cout << "Copy\n"; }
public:
FileSetting(std::string name, void * value, int size) { cout << "Create\n"; }
FileSetting(FileSetting &&fileSetting) { cout << "Move\n"; }
~FileSetting() { cout << "Destroy\n"; }
void test() { cout << "Test\n"; }
};
int main()
{
vector<FileSetting> settings;
{
char * test = "test";
FileSetting setting("test", test, strlen(test) * sizeof(char));
settings.push_back(std::move(setting));
}
settings[0].test();
cout << "Done!\n";
return 0;
}
The output will be:
Create
Move
Destroy
Test
Done!
Destroy
How can I make sure that destroy only will be called when FileSetting goes out of scope and not when I move it. I'm trying to avoid pointer.
std::move() doesn't destroy the object. The "Destroy" you're getting is from setting going out of scope.
Why does this work:
#include "iostream"
class Something {
private:
static int s_nIDGenerator;
int m_nID;
friend int main();
public:
Something() { m_nID = s_nIDGenerator++; }
int GetID() const { return m_nID; }
};
int Something::s_nIDGenerator;
int main() {
Something::s_nIDGenerator = 1;
Something cFirst;
Something cSecond;
Something cThird;
using namespace std;
cout << cFirst.GetID() << endl;
cout << cSecond.GetID() << endl;
cout << cThird.GetID() << endl;
return 0;
}
it prints:
1
2
3
And this fail:
#include "iostream"
namespace test {
class Something {
private:
static int s_nIDGenerator;
int m_nID;
friend int main();
public:
Something() { m_nID = s_nIDGenerator++; }
int GetID() const { return m_nID; }
};
};
int test::Something::s_nIDGenerator;
int main() {
using namespace test;
Something::s_nIDGenerator = 1;
// or test::Something::s_nIDGenerator = 1; same effect if not using using.
Something cFirst;
Something cSecond;
Something cThird;
using namespace std;
cout << cFirst.GetID() << endl;
cout << cSecond.GetID() << endl;
cout << cThird.GetID() << endl;
return 0;
}
With the compiler error message of:
**** Internal Builder is used for build ****
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src\tuttest1.o ..\src\tuttest1.cpp
..\src\tuttest1.cpp: In function 'int main()':
..\src\tuttest1.cpp:23:5: error: 'int test::Something::s_nIDGenerator' is private
..\src\tuttest1.cpp:27:13: error: within this context
Build error occurred, build is stopped
Time consumed: 161 ms.
How do I get the 2nd example to work using the namespace test?
How/Why is the namespace declaration around the object preventing the static member form being accessible?
Per my comment to #zmo, here is what I got to work based on his clue:
(comment doesn't have the space or formatting for this, and I had to edit because I couldn't set this an answer.... (what ever it takes.)
#include "iostream"
namespace test {
class Something {
private:
static int s_nIDGenerator;
int m_nID;
friend void load(int);
public:
Something() { m_nID = s_nIDGenerator++; }
int GetID() const { return m_nID; }
};
int Something::s_nIDGenerator;
void load (int value) {
Something::s_nIDGenerator = value;
}
};
int main() {
using namespace test;
load (1);
Something cFirst;
Something cSecond;
Something cThird;
using namespace std;
cout << cFirst.GetID() << endl;
cout << cSecond.GetID() << endl;
cout << cThird.GetID() << endl;
return 0;
}
I am still a little loose as to the "what's up with static members being in a class and a namespace not working?" What's up with this? Why didn't test::Something::s_nIDGenerator work? (still a part of my original question.) So, we are half-answered, so far.
I want to know why this didn't work so I don't walk into this rake again.
Probably because your friend int main() declaration is declaring that the namespace also has a free main() function, while the real main() function is not in the namespace.
To fix it? First declare int main(); before (and outside) namespace test, then friend int ::main() to indicate it's in the global namespace.
For more details, see this question.
well, though I will never recommand you to do like you did in your question, here is how to make your code work "as is" :
#include <iostream>
int main(); // declare main beforehands so it can be seen by Something
namespace test {
class Something {
private:
static int s_nIDGenerator;
int m_nID;
friend int ::main(); // take the main from global namespace
public:
Something() { m_nID = s_nIDGenerator++; }
int GetID() const { return m_nID; }
};
};
int test::Something::s_nIDGenerator;
int main() {
using namespace test;
Something::s_nIDGenerator = 1; // tada that works
Something cFirst;
Something cSecond;
Something cThird;
using namespace std;
cout << cFirst.GetID() << endl;
cout << cSecond.GetID() << endl;
cout << cThird.GetID() << endl;
return 0;
}
but here is a wrong use case of a friend function. The solution that seemed to work for you that I suggested (use a function inside your class Something) is far better for readability and understandability.
I hope I got the relevant code in here. I have some problem when I want to fetch the menu option that I've added into to menu_1. I have this function on_select(int) that I use to fetch one sub-menu's options, which I do by using the display() function. But when I compile it will say that there are no function named display() in menu_option() class, which is the Base class, but what I want to is to access the display() function which is located in the sub_menu() class.
I have tried multiple thing to get the relevant object from the array without any success, so I'm here now asking for help with this one.
I have this following main()
#include <iostream>
using namespace std;
#include "menu.h"
int main()
{
sub_menu* main_menu = new sub_menu("Warehouse Store Menu");
sub_menu* menu_1 = new sub_menu("Menu1");
main_menu->add_option(new sub_menu("Menu2"));
main_menu->add_option(menu_1);
product_menu->add_option(new add_item("sub_item1"));
product_menu->add_option(new add_item("sub_item2"));
product_menu->add_option(new add_item("sub_item3"));
main_menu->display();
main_menu->on_select(1);
delete main_menu;
return 0;
}
header file
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
const int MAX_SIZE = 9;
class menu_option
{
public:
menu_option(string const& n) : title(n) {};
virtual ~menu_option();
virtual void on_select(int) = 0;
string get_title() { return title; }
protected:
string title;
};
/* ------------------------------------- */
class sub_menu : public menu_option
{
public:
sub_menu(string const& n)
: menu_option(n) { no_item = 0; }
~sub_menu() { delete[] list; };
void on_select(int);
void add_option(menu_option*);
void display();
private:
menu_option* list[MAX_SIZE]; //container for options in the sub_menu
int no_item;
};
implement file
void sub_menu::on_select(int i)
{
cout << (list[i])->get_title() << endl;
cout << (list[i])->display() << endl; //<------ Doesn't work
}
void sub_menu::add_option(menu_option* item)
{
list[no_item] = item;
no_item++;
}
void sub_menu::display()
{
cout << ">> " << get_title() << " <<"<< endl;
for( int i = 0; i < no_item; i++ )
{
cout << setw(2) << i << ": " << (list[i])->get_title() << endl;
}
}
You can do what you want to do, but it's bad. You have to cast down to sub_menu when you call display() in on_select(). Of course it's not going to work the way you have it, and the compiler is telling you exactly why.
The other option, which is probably better (though without a clear understanding of the problem space may not be the best) would be to add display() as a virtual function to the menu_option class.
To solve your immediate problem you'll want to use dynamic_cast to turn a menu_option* into a sub_menu*, like so:
sub_menu* submenu(dynamic_cast<sub_menu*>(list[i]));
Note that if the cast fails (i.e., the menu_option pointed to by list[i] is not a sub_menu after all) the value of the submenu pointer will be NULL, so make sure you check that it is a valid pointer before using it in subsequent code.