An issue I keep facing is one where the compiler complains about an unused variable, even though the variable is used, but it's only used inside a parameter pack expansion that happens to be empty for a specific instantiation.
For example:
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var = get_tuple();
return func2(std::get<I>(var)...);
}
auto a = func1(std::make_index_sequence<0>());
See live example (try changing the tuple at line 4, by adding an int inside <> to see the warning go away).
I know I could add a (void)var; line to make the warning go away, but it feels dirty to me, especially when the function is actually just a single line.
I also don't want to disable this warning globally, because it does provide insight sometimes.
A similar manifestation of this issue is when the variable is used in a lambda capture. In this case, gcc spits no warning, while clang complains (I think gcc never implemented a warning about unused lambda captures):
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var = get_tuple();
auto my_lambda = [var](){
return func2(std::get<I>(var)...);
};
return my_lambda();
}
auto a = func1(std::make_index_sequence<0>());
clang example
If you can use C++17, the [[maybe_unused]] attribute is the clearest solution IMO:
[[maybe_unused]]
auto tuple = get_tuple();
var is indeed not use with empty pack.
Is it intended ? compiler can only guess.
Whereas clang consider than empty pack is a usage, gcc chooses the contrary.
You can silent the warning in different ways as:
attribute [[maybe_unused]] (C++17)
casting to void (static_cast<void>(arg))
or similar (template <typename T> void unused_var(T&&){} and then unused_var(var)).
creating overloads:
auto func1(std::index_sequence<>)
{
return func2();
}
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var = get_tuple();
return func2(std::get<I>(var)...);
}
or in C++17
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
if constexpr (sizeof ...(I) == 0) {
return func2();
} else {
auto var = get_tuple();
return func2(std::get<I>(var)...);
}
}
This seems to be a compiler bug in GCC. The easiest workaround is to mark var with [[gnu::unused]]:
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var [[gnu::unused]] = get_tuple();
return func2(std::get<I>(var)...);
}
If you are force to use compilers that don't recognize [[gnu::unused]], you can fake use the variable with a static_cast<void>:
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var = get_tuple();
static_cast<void>(var);
return func2(std::get<I>(var)...);
}
(void)var; suppressed unused warnings in every compiler I have used:
template <std::size_t... I>
auto func1(std::index_sequence<I...>)
{
auto var = get_tuple();
(void)var;
return func2(std::get<I>(var)...);
}
auto a = func1(std::make_index_sequence<0>());
(void)variable; has zero run time effects.
Maybe there are other problems but... according the code you linked in compiler explorer, your var is a std::tuple<>; that is a std::tuple with zero components.
If I'm not wrong, std::get<Num>(std::tuple<Ts..>) is defined only when Num is in [0,sizeof...(Ts)); in this case in [0, 0), that is an empty interval.
I suppose that your code (when var is defined as std::tuple<>) is ill formed. So I suppose that the warning is correct (because there isn't cases when var is used) but doesn't warn about the real problem.
It's different when var is defined as std::tuple<int>: var is correctly used when all I are equal to zero, so var is (potentially) used and, as you observed, the warning disappears.
Related
I have a struct A that inherits from other classes (which I'm not allowed to change). Inside A and it's methods I can call inherited methods (lets say A_method(int i), for example) without problem but when I tried to write a nested struct (lets say In) and call A_method(int i) and there is were I'm stuck.
The initial code looks like this, and I can't change it, is some kind of college assigment.
#include "Player.hh"
struct A : public Player {
static Player* factory () {
return new A;
}
virtual void play () {
}
};
RegisterPlayer(PLAYER_NAME);
Then I tried this:
#include "Player.hh"
struct A : public Player {
static Player* factory () {
return new A;
}
//My code
struct In {
int x;
void do_smthing() {
A_method(x);
}
}
virtual void play () {
}
};
RegisterPlayer(PLAYER_NAME);
Ok, from a beginning I knew I could't do this, for In to see it's parent class it should have a pointer to it but In is a often instantiated object in my code and I wanted to avoid passing this constantly to a constructor so I tried this aproach:
#include "Player.hh"
struct A : public Player {
static Player* factory () {
return new A;
}
//My code
static struct Aux
A* ptr;
Aux(A* _p) { ptr = _p; }
} aux;
struct In {
int x;
void do_smthing() {
aux.ptr->A_method(x);
}
}
virtual void play () {
//the idea is to call do_smthing() here.
}
};
RegisterPlayer(PLAYER_NAME);
What I want to avoid (if possible) is something like this:
struct In {
int x;
A* ptr;
In (A* _p) : ptr(_p) {}
void do_smthing() {
ptr->A_method(x);
}
}
The main reason for this: I have more struct definitions and they they are instantiated multiple times through the rest of the (omitted) code, and I don't like the idea of seeing In(this) so many times.
I don't know if I'm completly missing something or what I want to do it's just not possible... Please ask for clarifications if necessary.
(Also, performance is kind of critical, my code will be tested with limited CPU time so I kinda have to avoid expensive approachs if possible. Using C++11)
There is no way you can skip passing the this pointer. Instead, you could create a helper function in A:
template <typename InnerType, typename ...Params>
InnerType makeInner(Params&&... params)
{
return InnerType(this, std::forward<Params>(params)...);
}
Then you can use
auto * a = A::factory();
auto inner = a->makeInner<A::In>();
I have some suggestions which are not directly related to you question but may help:
A::facotry() returns a std::unique_ptr<A> instead of raw pointer
Try to describe what problem you are trying to solve. I have a strong feeling that there can be a better design other than creating many nested structs.
I don't see passing a this pointer could have any impact on the performance. The more important thing is to identify the path that is latency-sensitive and move expensive operations out of those paths.
I am inspecting the code that may cause memory leak. I know something is wrong with std::set.erase(this) and the destructor of SomeObject. So how to fix it?
class SomeObject;
////....
std::set<SomeObject*> managedObjects;
///.....
class SomeObject{
public:
SomeObject(){ managedObjects.insert(this); }
SomeObject(SomeObject&& S)/*move cter*/{ managedObjects.insert(this); }
virtual ~SomeObject() { managedObjects.erase(this); }
////....
};
////....
void clearAllObjects() {
for(auto p : managedObjects){
if(p){
delete p;
}
}
managedObjects.clear();
}
////....
When you delete inside clearAllObjects() it will result in managedObjects.erase(this) which is the same as managedObjects.erase(p).
This means that the internal iterator in the range based for-loop may be invalidated (I'm not sure). If it is, it'll try to do ++internal_iterator; on an invalid iterator - with undefined behavior as a result.
To be safe, you could copy the iterator and step that to the next in the set before doing erase.
Also note: There's no need to check if what you delete is a nullptr or not. It's mandated by the standard to have no effect if that's the case.
Example:
void clearAllObjects() {
for(auto pit = managedObjects.begin(); pit != managedObjects.end();) {
delete *pit++ // postfix ++ returns a copy of the old iterator
}
managedObjects.clear();
}
A side effect by having this managedObjects set is that you can't have automatic variables of SomeObject.
int main() {
SomeObject foo;
clearAllObjects(); // deletes the automatic object "foo" (not allowed)
} // <- the automatic object is destroyed here
There is a custom defined map, with an element std::function()>.
The lambda code is working, but I don't know how to expand it to a normal formation. The code is following.
class TestA{
public:
TestA() {}
~TestA() {}
TestA(const TestA &) {}
static void print()
{
cout << __FUNCTION__ << endl;
return;
}
};
void testComplexMap1()
{
typedef map<string, std::function<std::unique_ptr<TestA>()>> TempMap;
TempMap m;
// the lambda format code, it works
//m.insert({ "TestA", []() {return std::unique_ptr<TestA>(new TestA());}});
// I want to expand it, but failed.
TestA *t = new TestA();
//function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t));
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)()); //warning here
//m.emplace("TestA", fp); // compile error here
}
Any help will be greatly appreciated.
fp is not initialized with a function so compilation fails.
You can expand it like this:
TestA *t = new TestA();
std::unique_ptr<TestA> UT(t);
auto func = [&]() { return move(UT);};
std::function<std::unique_ptr<TestA>()> fp(func);
m.emplace("TestA", fp);
See DEMO.
In C++ everything that looks like it could be a declaration is treated as such.
This means the line
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)());
is interpreted as:
fp is the declaration of a function returning an std::function<unique_ptr<TestA>()> and expecting a parameter called t which is a function pointer to a function returning a std::unique_ptr<TestA> and getting no parameter. (Which is not what you intended.)
This also means that the t in this line is not the same t as in the previous line.
You have to pass fp something that is actually callable like this:
std::unique_ptr<TestA> f() {
return std::make_unique<TestA>();
}
void testComplexMap1() {
// ...
function<unique_ptr<TestA>()> fp(f);
m.emplace("TestA1", fp);
}
If you want to add a function to the map that wraps an existing pointer into a unique_ptr you would need either a functor:
class Functor {
public:
Functor(TestA * a) : m_a(a) {}
~Functor() { delete m_a; }
std::unique_ptr<TestA> operator()(){
auto x = std::unique_ptr<TestA>(m_a);
m_a = nullptr;
return std::move(x);
}
private:
TestA * m_a;
};
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", Functor(t));
}
Or a lambda with capture:
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", [t](){ return std::unique_ptr<TestA>(t); });
}
The lamda is translated more or less to something like the Functor class. However in each case you have to be really careful: The functions in the map that encapsulate an existing pointer into a std::unique_ptr can and should only be called once.
If you don't call them, memory allocated for t won't be freed. If you call them more than once you get either a std::unique_ptr to nullptr (in my Functor class variant) or a more than one std::unique_ptr tries to manage the same memory region (in the lambda with capture variant), which will crash as soon as the second std::unique_ptr is deleted.
In short: I would advice against writing code like this and only put functions in the map that are callable multiple times.
I would like to benchmark the performance of using a const cache for some static function inside a cache. So I have something like that:
class Foo {
static double cost(int factor) { <moderately complex function> };
// Other stuff using the cost() function
};
And I would like to benchmark against an alternative version like this one:
class Foo {
private:
static double _cost(int factor) { <same function as before> };
static const double cost_cache[MAX_FACTOR] = ???;
public:
static double cost(int factor) { return cost_cache[factor]; };
// Other stuff
}
With a way to initialize my cost_cache array in a way equivalent to
for (int idx = 0; i < MAX_FACTOR; ++i)
cost_cache[idx] = _cost(idx);
In a high-level functional language I would use a map primitive. How do I properly initialize that in C++11 (or C++14 ?) I saw other posts addressing similar questions, like Initializing private member static const array, but its solution is inapplicable in my case, I can't put the 10k values verbatim in source.
I'm using clang++
What about first initialize the array with "{}",
and then overwrite elements by a method that loads values from a file?
I wrote a class method using STL find_if. The code is the following:
void
Simulator::CommunicateEvent (pEvent e)
{
pwEvent we (e);
std::list<pEvent> l;
for (uint32_t i = 0; i < m_simulatorObjects.size (); i++)
{
l = m_simulatorObjects[i]->ProcessEvent (we);
// no action needed if list is empty
if (l.empty ())
continue;
// sorting needed if list comprises 2+ events
if (l.size () != 1)
l.sort (Event::Compare);
std::list<pEvent>::iterator it = m_eventList.begin ();
std::list<pEvent>::iterator jt;
for (std::list<pEvent>::iterator returnedElementIt = l.begin ();
returnedElementIt != l.end ();
returnedElementIt++)
{
// loop through the array until you find an element whose time is just
// greater than the time of the element we want to insert
Simulator::m_eventTime = (*returnedElementIt)->GetTime ();
jt = find_if (it,
m_eventList.end (),
IsJustGreater);
m_eventList.insert (jt, *returnedElementIt);
it = jt;
}
}
}
Unfortunately, I later discovered that the machine that will run the code is equipped with the libstdc++ library version 4.1.1-21, which apparently is lacking find_if. Needless to say, I cannot upgrade the library, nor can I ask someone to do it.
When compiling, the error I get is:
simulator.cc: In member function ‘void sim::Simulator::CommunicateEvent(sim::pEvent)’:
simulator.cc:168: error: no matching function for call to ‘find_if(std::_List_iterator<boost::shared_ptr<sim::Event> >&, std::_List_iterator<boost::shared_ptr<sim::Event> >, sim::Simulator::<anonymous struct>&)’
simulator.cc: In static member function ‘static void sim::Simulator::InsertEvent(sim::pEvent)’:
simulator.cc:191: error: no matching function for call to ‘find_if(std::_List_iterator<boost::shared_ptr<sim::Event> >&, std::_List_iterator<boost::shared_ptr<sim::Event> >, sim::Simulator::<anonymous struct>&)’
make: *** [simulator.o] Error 1
How can I solve the problem?
I thought I could define a find_if function as described here. However, I have some concerns:
What about performance? The function that makes use of find_if needs to be as efficient as possible.
How can I do conditional compilation? I couldn't find a macro telling the version of the libstdc++ installed.
What are your thoughts about it?
TIA,
Jir
References
Source files: simulator.h and simulator.cc
Solution
Defined IsJustGreater outside the Simulator class and declared IsJustGreater_s friend of Simulator:
struct IsJustGreater_s : public std::unary_function<const pEvent, bool> {
inline bool operator() (const pEvent e1) {return (e1->GetTime () > Simulator::m_eventTime);}
} IsJustGreater;
Called IsJustGreater in find_if this way:
jt = find_if (it, m_eventList.end (), sim::IsJustGreater);
From the error, it appears that you're attempting to use an anonymous type as the argument. I do not believe anonymous types are allowed to be template arguments.
From the error, I believe you have something like this:
class Simulator {
struct {
bool operator(const pEvent& p) { ... } ;
} IsJustGreater;
}
what you want is to give it a name and then change the find_if to instantiate the class (see below)
class Simulator {
// class is now an inner named-class
struct IsJustGreater {
bool operator(const pEvent& p) { ... } ;
};
}
// This is how you use the class
jt = std::find_if(it, m_eventList.end(), IsJustGreater() );
I see that you're using the std:: qualifier before std::list but not std::find_if. Try putting the std:: in front so that the compiler can find it within the namespace.