In order to do some custom memory tracking (leak prevention, corruption detection), I'm having to use placement new to create C++ objects, which works fine - but I'm struggling to figure out how I can pass arguments to the constructor, since it's called from a macro (so the file + line can be provided automatically).
The function:
template <typename T>
T*
cpp_new(
const char *file,
size_t line
)
{
T *n = (T*)tracked_allocate(&memory_context, sizeof(T), file, line);
if ( n )
{
construct(n);
}
else
{
throw std::bad_alloc();
}
return n;
}
This is called via the macro:
#define new_object(type) cpp_new<type>(__FILE__, __LINE__)
Placemented new:
template <typename T>
void
construct(
T *obj
)
{
obj = new (obj) T;
}
The va_list macros would cover the expansion for the variable number of arguments, only I don't want to supply the number of arguments the constructor has, removing va_arg(), and can't use va_start(), since it expects a format.
This went a little over my head: http://www.drdobbs.com/cpp/calling-constructors-with-placement-new/232901023?pgno=2
Is there any way I can use __VA_ARGS__ from new_object and pass them into the construct function? Each object only has one constructor, but there are many different types of objects taking different parameters, so I want to remove as much manual maintenance as possible.
Or is there just a better way in general of doing what I'm attempting!
You should not deal with the construct-if-allocation-succeeded. That's the job of a new-expression. It does that correctly, as a transaction-like operation: either all succeeds, or cleanup is performed before the exception is propagated.
So, relieved of that responsibility, the job of your macro is to do that which only macros can do, namely picking up the filename and line.
Those items can/should be passed to allocator function, which then technically is a "placement new", although here it will not construct in-place: it's a placement new merely because it has extra, user-defined arguments, like this:
bool hopefully( bool const c ) { return c; }
template< class X >
bool throw_( X const& x ) { throw x; }
void* operator new( size_t const size, char const* const filename, int const linenum )
{
void* const p = tracked_allocate( &memory_context, size, filename, linenum );
hopefully( p != 0 )
|| throw_( std::bad_alloc() )
return p;
}
You need to define a corresponding placement deallocation function, or else a new expression will fail to deallocate when a constructor throws:
void operator delete( void* const p )
{
// Your custom deallocation.
}
void operator delete( void* const p, char const*, int )
{
::operator delete( p );
}
Now your macro just needs to provide the relevant placement arguments, like this:
#define SOURCE_LINE_INFO __FILE__, __LINE__
Then you can just say, like,
new (SOURCE_LINE_INFO) MyType( arg1, arg2, arg3 )
For a more reusable solution consider defining a struct to hold the filename and line number. Then the macro reduces to constructing an instance of that type, and can be used more generally. In particular, it can then be used for logging calls.
Related
I am using a library function that expects an array of pointers (void**) at some point, it works more or less like this.
void* args[] = { &var_a, &var_b, &var_c, ... };
someFunction(args);
After using it once, I would like to call the same function again, so what I do is create another variable like:
void* args_2[] = { &var_d, &var_e, &var_f, ... };
someFunction(args_2);
And so on ...
I would like to find a way to recycle the args symbol, so I don't have to do args_2, args_3, args_4 every time I call it; but when I try to reassign it like:
args = { &var_d, &var_e, &var_f, ... };
I get the following:
error: assigning to an array from an initializer list
I understand the error but I don't know how to avoid it or coerce this thing into the intended array of pointers type.
I know they are two different languages, but I am looking for a solution that works in both C and C++.
Why use a local variable at all, if you only need it once to call someFunction?
using args = void *[];
someFunction(args{&a, &b});
someFunction(args{&a, &b, &c});
Alternatively, C++ify this a bit more with a wrapper:
template <class... T>
decltype(auto) someFunction(T *... args) {
void *args_[] { args... };
return someFunction(args_);
}
someFunction(&a, &b);
someFunction(&a, &b, &c);
You could make use of compound literals as below with pointer to pointer.
void** args = (void *[]){ &var_a, &var_b, &var_c, ... };
args = (void *[]){ &var_d, &var_e, &var_f, ... };
I have a macro:
#define checkAlloc(ans) checkPointer((ans), __FILE__, __LINE__);
which is used to wrap around any pointer allocation to check it is valid (used for checking memory allocations on a GPU device side).
The macro is used as follows:
SomeObject* myObj = checkAlloc(new SomeObject());
and the checkPointer function is implemented as:
inline __device__ SomeObject* checkPointer(SomeObject* pointer, char *file, int line)
{
if (pointer == nullptr)
{
// do error logging
}
return pointer;
}
Now, it is very inconvenient to create a new version of the function for each type of object I might allocate to. Templates are also not an option since I would like syntax to be clear - i.e. just putting checkAlloc(…) around each allocation rather than checkAlloc<SomeObject>(…) which is ugly and hopefully unnecessary.
Ideally I would like to change the checkPointer to be:
inline __device__ auto checkPointer(auto pointer, char *file, int line)
but I understand auto cannot be used for a function parameter yet. The GPU code supports C++14 so lambdas could be used as a potential workaround from I can read at https://stackoverflow.com/a/29945034/7283981 but I am not familiar enough with lambdas to know how to do this. Any ideas?
This is the perfect case for a template, I don't understand why you are trying to avoid it:
template < typename T >
inline __device__ T* checkPointer(T* pointer, const char *file, int line)
{
if (pointer == nullptr)
{
// do error logging
}
return pointer;
}
This is very clear and clean and you can use it as if there was an auto there:
int main(int argc, char** argv)
{
SomeObject* myObj = checkAlloc(new SomeObject());
}
As you can see, there are automatic argument deduction capabilities that don't even require any type specification...
Oh, and notice that I changed char * file to const char * file as C++11 doesn't allow conversion of literals to char *
I have read about new and delete overloading for memory tracking in How_To_Find_Memory_Leaks
I defined these global operators:
inline void* __cdecl operator new( unsigned int size, const char *file, int line ) {
void* ptr = malloc( size );
AddTrack((DWORD)ptr, size, file, line);
return ptr;
}
inline void* __cdecl operator new( unsigned int size, void* ptr, const char *file, int line ) {
return ptr;
}
It works well with new and new[] operators, but i have a problem with placement new ( second one ). My define look like:
#define new new( __FILE__, __LINE__)
#define new(x) new( x, __FILE__, __LINE__)
They work separately. But when i try to use them both there are errors appear. As I understand they substitute each other. I know I can have macro with variable number of arguments like this:
#define new( ... ) new( __VA_ARGS__, __FILE__, __LINE__)
But I need the same macro with and without arguments at all, so both new-s in these lines substitute right:
g_brushes = new Brush[ num_brushes ];
...
new( &g_brushes[i] )Brush(sides);
If you decide to walk the dark path of overriding the global new, you have to make sure you consider all of the following scenarios:
new Foo; // 1
new Foo[10]; // 2
new (std::nothrow) Foo; // 3
new (p) Foo; // 4 - placement, not overridable
(Foo*) ::operator new(sizeof(Foo)); // 5 - direct invocation of the operator
And it should be possible to be able to handle all the above except for the last. Shudder.
The necessary knol and the sleight of hand is that your macro should end with new. When your macro ends with new, you can delegate the different ways it can be invoked to new itself.
Here's one, non-thread safe way to proceed. Define a type to capture the context of the invocation, so we will be able to retrieve this context later in the operator itself,
struct new_context {
new_context(const char* file, const int line)
: file_(file), line_(line) { scope_ = this; }
~new_context() { scope_ = 0; }
static new_context const& scope() { assert(scope_); return *scope_; }
operator bool() const { return false; }
const char* file_;
const int line_;
private:
static new_context* scope_;
};
Next, define your override to create a new_context temporary just before the invocation,
#define new new_context(__FILE__, __LINE__) ? 0 : new
using the ternary operator conditional assignment to evaluate an expression before delegating to the operator new, notice that it is where the operator bool that we have defined above comes handy.
Then inside your new overrides (I'll use standard C++98 here instead of the MSC C++), all you have to do is to retrieve the context:
void* operator new (std::size_t size) throw (std::bad_alloc) {
std::cout
<< "new"
<< "," << new_context::scope().file_
<< ":" << new_context::scope().line_
<< std::endl;
return 0;
}
This approach will deal with all the cases 1-4 from above, and what's important and can be easily overlooked is that in case 4 where your overloads are not invoked, as you cannot replace placement new (§18.4.1.3), you still know that placement new took place because new_context will be created and destroyed.
To summarise, you don’t need to modify what follows after the new operator, so all possible syntaxes remain valid. And the other point is that the new_context object temporary is going to be kept alive until the end of the expression the operator participates in, so you are safe to obtain it from a global singleton.
See a gcc example live. Adapting to MSC is left to the reader.
I have a method with the prototype:
bool getAssignment(const Query& query, Assignment *&result);
I am a bit confused about the type of the second param (Assignment *&result) since I don't think I have seen something like that before. It is used like:
Assignment *a;
if (!getAssignment(query, a))
return false;
Is it a reference to a pointer or the other way around ? or neither ? Any explanation is appreciated. Thanks.
It's a reference to a pointer. The idea is to be able to change the pointer. It's like any other type.
Detailed explanation and example:
void f( char* p )
{
p = new char[ 100 ];
}
int main()
{
char* p_main = NULL;
f( p_main );
return 0;
}
will not change p_main to point to the allocated char array (it's a definite memory leak). This is because you copy the pointer, it's passed by value (it's like passing an int by value; for example void f( int x ) != void f( int& x ) ) .
So, if you change f:
void f( char*& p )
now, this will pass p_main by reference and will change it. Thus, this is not a memory leak and after the execution of f, p_main will correctly point to the allocated memory.
P.S. The same can be done, by using double pointer (as, for example, C does not have references):
void f( char** p )
{
*p = new char[ 100 ];
}
int main()
{
char* p_main = NULL;
f( &p_main );
return 0;
}
For something like this, you basically read the declaration from right to left (or inside out).
In other words, you want to start from the name of the item being declared, then progress outward. In this case, progressing directly from the name to the type, we get:
This is a homework assignment. The Field container was the assignment from a week ago, and now I'm supposed to use the Field container to act as a dynamic array for a struct NumPair which holds two char * like so:
struct NumPair
{
char *pFirst, *pSecond;
int count;
NumPair( char *pfirst = "", char *psecond = "", int count = 0)
: pFirst(strdup(pfirst)), pSecond(strdup(psecond)), count(count)
{ }
NumPair( const NumPair& np )
: count(np.count), pFirst(strdup(np.pFirst)), pSecond(strdup(np.pSecond))
{ }
NumPair& operator=( const NumPair& np )
{
if(this != &np)
{
pFirst = strdup(np.pFirst);
pSecond = strdup(np.pSecond);
count = np.count;
}
return *this;
}
and the Field container
Field<NumPair> dict_;
The homework requires the use of char *, and not string, so that we can get better with all this low-level stuff. I've already had some question about char to wchar_t conversions, etc.
Now I have a question as to whether or not I'm destructing the NumPair properly. The scenario is as follows:
1) Field destructor gets called
template <class T>
Field<T>::~Field()
{
delete[] v_;
}
2) Delete calls the destructor of every element NumPair in v_;
~NumPair()
{
free(pFirst);
free(pSecond);
}
Is this okay? I haven't really read too many articles about mixing and matching elements created on the heap and free-store as we wish. I figure as long as I don't use delete on an improper malloc'ed element, I should be fine.
However, I don't know the entire intricacies of the delete command, so I'm wondering whether or not this is valid design, and what I could do to make it better.
Also, of course this isn't. I'm getting an error of the type:
This may be due to a corruption of the heap and points to dbgheap
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); // Here
}
Again, how could I improve this without the use of string?
FIELD CTOR/Copy Ctor/Assignment
template <class T>
Field<T>::Field()
: v_(0), vused_(0), vsize_(0)
{ }
template <class T>
Field<T>::Field(size_t n, const T &val)
: v_(0), vused_(n), vsize_(0)
{
if(n > 0)
{
vsize_ = 1;
while(vsize_ < n)
vsize_ <<= 1;
v_ = new T[vsize_];
std::fill(v_, (v_ + vused_), val);
}
}
template <class T>
Field<T>::Field(const Field<T> &other)
: v_(new T[other.vsize_]), vsize_(other.vsize_), vused_(other.vused_)
{
std::copy(other.v_, (other.v_ + other.vused_), v_);
}
template <class T>
Field<T>& Field<T>::operator =(const Field<T> &other)
{
this->v_ = other.v_;
this->vused_ = other.vused_;
this->vsize_ = other.vsize_;
return *this;
}
FIELD MEMBERS
T *v_;
size_t vsize_;
size_t vused_;
Your copy constructor (of Field<>) seems OK, but the operator= is problematic.
Not only does it leak memory (what happens to the original v_?), but after that, two instances of Field<> hold a pointer to the same block of memory, and the one that is destructed first will invalidate the others v_ - and you can't even tell whether that has happened.
It's not always easy to decide how to deal with operator= - some think that implicit move semantics are okay, but the rest of us see how that played out with the majority of people, with std::auto_ptr. Probably the easiest solution is to disable copying altogether, and use explicit functions for moving ownership.
Your string handling in NumPair looks ok (strdup + free) and your Field container delete[] looks okay but it's hard to say because you don't show what v_ is.
eq mentions in a comment that you should also beware of how you are copying NumPairs. By default, C++ will give you an implicit member-wise copy constructor. This is where a RAII type like std::string makes your life easier: Your std::string containing struct can be copied without any special handling on your part and memory referenced in the string will be taken care of by the string's copy. If you duplicate your NumPair (by assigning it or returning it from a function for example) then the destruction of the temporary will free your strings out from under you.
Your copy constructor for Field just copies the pointers in v_. If you have two copies of a Field, all of the NumPairs in v_ will be deleted when the first Field goes out of scope, and then deleted again when the second one does.