I've been looking into smart pointers, unit testing how they manage memory and am finding and unexpected issue that all the examples recommend doing, but it creates a huge memory leak for me.
This seems to occur when I use a class that has a constructor that builds from another copy of the same class. I'll give an example.
If I have a class like:
Class foo{
public:
//Ignore unsafe practices here
HeavyInMemory* variable;
foo(){
variable = new HeavyInMemory();
}
foo(foo* copyThis){
variable = nullptr;
if(copyThis){
variable = new HeavyInMemory(copyThis->variable);
}
}
~foo(){
delete variable;
}
}
I find that I will get a huge memory leak because std::make_shared has no way to tell the difference between make_shared(args) and make_shared(new T)
Main(){
for(int i =0; i < 100; i++{
//Should not leak, if I follow examples of how to use make_shared
auto test = make_shared<foo>(new foo());
}
//Checking memory addresses these do not match, checking total program memory use, leaks like a
//sieve.
}
Am I misunderstanding something?
Do the examples just not consider this as most use primitive types as examples rather than classes.
Does c++11 just not support the make_shared(new T) format even though I see old books like scott meyers books from 1992. It just doesn't make sense.
Also why would you use make_shared(new T) over make_shared(args)? I've seen a couple threads where people have asked this on here, but neither seemed to actually answer the question with a code example.
//As they mainly say code compiler order causes the leak but in my example this would still leak:
auto originalObject = new foo();
auto expectedDestructorWhenOutofScope = make_shared<foo>(originalObject);
//I have found if I give if the object instead it doesn't leak, but this is getting into the realms of
//hacks that may sometimes work
auto originalObject = new foo();
auto expectedDestructorWhenOutofScope = make_shared<foo>(*originalObject);
EDIT:
Thanks to Igor Tandetnik I now see I am using make_shared entirely wrong. It should be used as a constructor. Thanks again Igor I appreciate it.
//Create new
auto expectedDestructorWhenOutofScope = make_shared<foo>();
//Use object already created
std::shared_ptr<Object> p2(new foo())
Given this issue-exemplifing minimal code:
#include <fstream>
#include <string>
using std::ifstream;
using std::string;
string TEST_PATH;
string TRAIN_PATH;
enum DataContext
{
TRAINING, TESTING
};
void StreamData(DataContext context)
{
ifstream dataFile = (context == TRAINING) ? ifstream(TRAIN_PATH) : ifstream(TEST_PATH);
dataFile.close();
}
void StreamData2(DataContext context)
{
ifstream datafile;
datafile.open((context == TRAINING) ? TRAIN_PATH: TEST_PATH);
datafile.close();
}
int main()
{
StreamData(TRAINING);
StreamData2(TRAINING);
return 0;
}
I am implementing an AI Iterative Dichotomizer, but that isn't relevant to this issue. What is relevant are two external testfiles, one with training data and one with testing data. Certain control flow is governed by what type of data is being dealt with at the time, a simple enum is used to simplify such association.
StreamData aims to conditionally direct initialize an ifstream based on a check of the current context. It does so with the ternary operator. In Visual Studio(which means nothing), but also in cygwin g++ v5.1.0, the use of the StreamData function as written compiles successfully, and executes per my expectations.(in my real program, something is actually returned). However, in Debian, g++ v4.9.2, the use of that function produces an essay of compiler-ese. I won't copy the whole output, unless it becomes necessary, but the highlights include a warning that g++ is deleting the default ifstream constuctor because it would be ill-formed. Then a forceful criticism of attempting to call a deleted function.
"g++ -o TT -std=c++11 ./ThisCode.cpp" is the g++ command executed in both environments.
StreamData2 is a natural alternative to StreamData, and it compiles fine everywhere.
My problem is solved with StreamData2. I'm left with a question. Is StreamData valid C++11/use of the ternary operator? Is compilation failure with the lesser revision of g++ a bug/mal-implementation?
Thanks for any insight.
Referring to my previous question, as the explanation is required in detail.
How is the following code snippet working, fundamental and C++ 03 equivalent ?
auto get_option_name = [](const std::pair<const std::string, std::string>& p) -> const std::string& {
return p.first;
};
It's equivalent to:
class Extractor {
// Definition of "function call" operator, to use instance
// of this class like a function
const std::string& operator()(const std::pair<const std::string, std::string>& p) {
return p.first;
}
};
Extractor get_option_name;
More information on wikipedia or on stackoverflow
#Garf365's answer is the best. A lambda and a class like that one really are the most similar - you can use them just like callable functions, and pass around pointers and references to them.
However, you may also want to learn about using function templates to do this work during compile-time, especially when passing them as a parameter to another template, as in using the boost library.
I was curious if there was an improvement in the complexity of the code the compiler produced by using a function template, and there was!
Look for yourself:
Using a "function object" or "functor" class (or whatever they are called) - is 187 lines of assembly from GCC, and 237 lines of assembly from clang.
Using a function template - only 65 lines of assembly from GCC, and 84 from clang. That's a reduction by a factor of 300%!
Thank you for asking the question and leading me to look into it!
I would like to store some closures in an array.
I tagged the question MSVC10 since it seems that according to c++11 closures should be compatible (at least under some conditions) with function pointers but MSVC10 does not supports that.
Is there a way around this limitation?
example:
typedef double (*Func)(const C* c);
struct Feature{
Feature(FeatureId i_id = None, const QString& i_name=QString(), Func i_ex = nullptr)
:id(i_id),name(i_name), extraction(i_ex)
{}
FeatureId id;
QString name;
Func extraction;
};
QList<Feature> features;
features.append(Feature(feat_t, "a/t", [](const C* c) -> double{return c->a.t;} ));
I want to be able to assign closures to the function pointer because i do not want to define dozens of separate functions.
Thanks in advance for your suggestions.
You should use std::function<double(const C*)> (see this) instead of Func, so
struct Feature{
FeatureId id;
QString name;
std::function<double(const C*)> extraction;
/// etc...
};
You may need to upgrade your compiler (I guess that Visual Studio 2010 appeared before the C++11 standard, but I never used Windows or other Microsoft products). Did you consider using a recent GCC (4.9 at least) or a recent Clang/LLVM (3.5) ?
If you cannot upgrade your compiler, stick to C++98 and don't use C++11 features.
By definition, a closure is more heavy that a function pointer, since it contains closed values (some of which might be hidden or non-obvious).
The warning is produced by the c code generated by vala.
warning: missing braces around initializer
The code works but the warning is annoying. The vala code referenced by the warning is
struct Position {uint x; uint y;}
private static Position positions[8];
The generated C code is
static Position det_positions[8] = {0};
I've tried initializing positions half a dozen different ways but can't seem to get the syntax to satisfy the warning. Is this GCC bug 53119 or is there a way to fix it?
Yes, this appears to be related to GCC bug 53119. It goes away if you change the C declaration to {{0}}. Your options are:
Ignore the warning.
Manipulate the C code after generation to have {{0}} instead of {0} on that line using sed or the like.
Declare the array extern in Vala, and write the C definition elsewhere. (The permanent version of #2.)
Do something like struct foo { int bar; Position positions[8]; } static foo position_holder and {0} will then be initialising position_holder.bar which is fine and the warning goes away.
This warning also appears when a multi-dimensional array is treated as a linear array ( although it is still correct and the code runs perfectly ) with -Wall compiler flags set.
For example
char array[5][10][2] = {\
"0","0","0","0","0","0","0","0","0","0",\
"1","1","1","1","1","1","1","1","1","1",\
"2","2","2","2","2","2","2","2","2","2",\
"3","3","3","3","3","3","3","3","3","3",\
"4","4","4","4","4","4","4","4","4","4" };
This will generate the warning.
Do the following changes to remove the warnings as shown below
char array[5][10][2] = {\
{"0","0","0","0","0","0","0","0","0","0" },\
{"1","1","1","1","1","1","1","1","1","1"},\
{"2","2","2","2","2","2","2","2","2","2"},\
{"3","3","3","3","3","3","3","3","3","3"},\
{"4","4","4","4","4","4","4","4","4","4"} };
Please do correct me if I am wrong.