I am trying to determine what the strictly conforming pattern for using memory allocators with C++17 is. Specifically, moving away from the working in practice UB pattern:
example * foo = (example*)malloc(sizeof(example)); // no object here, don't use foo!
Therefore placement new into the allocated memory. Something like:
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <new>
struct example { // alignment <= max_align_t
example(int x) : x(x) {}
~example() {}
int x;
static void *operator new(size_t, example *p) { return p; }
};
int main() {
example *ex = nullptr;
{
void *m = malloc(sizeof(example));
if (!m) {
return 1;
}
ex = new (reinterpret_cast<example *>(m)) example(42);
// if one failed to store the result of the new expression, can retrieve it
// from m via launder
ex = std::launder(reinterpret_cast<example *>(m));
// now abandon all further instances of 'void *m'
}
// ... do some well defined things with the example object at *ex
All good, we have a properly constructed object. How do we free it?
// ...
{
ex->~example(); // lifetime has ended
// UB? We don't have a void* to pass to free
// free(ex);
// equivalent to above, it's still not a void*
// free(reinterpret_cast<void*>(ex));
// error, new defines: void launder(void*) = delete
// free(std::launder(reinterpret_cast<void*>(ex)));
// error: void pointer argument to __builtin_launder is not allowed
// free( __builtin_launder(reinterpret_cast<void*>(ex)));
// Quoting the rule book, 21.6.4 [ptr.launder]
// The program is ill-formed if T is a function type or cv void
// Out of options, guess it has to be free
free(ex);
}
}
void * doesn't have the aliasing properties of a char*. Can't even do arithmetic on void*.
'Free' is a difficult thing to search for. I can't see special case magic for free, but even if there is such, it won't help with platform_allocate/platform_deallocate pairs.
On the basis that launder definitely doesn't permit one to get the void* back, free(ex) in the above is presumably the right thing to do.
What makes free(ex) well defined?
Why is launder(void) forbidden? A pointer optimisation barrier applied at the end of the malloc() implementation seems a great idea.
What makes free(ex) well defined?
free requires a pointer whose address is one directly returned by a call to malloc. You have provided that. Why wouldn't it work?
Why is launder(void) forbidden?
Because it makes no sense. std::launder<T> returns a pointer to an object of type T within its lifetime whose address is the address of the given pointer. void is an incomplete type; there cannot be objects of type void. Therefore, std::launder<void> cannot possibly function.
Memory allocation functions typically do not deal with pointers to objects. They deal in pointers to memory. The only thing they care about is whether the address of that pointer is one they can deal with.
Related
I want to create an instance of a class using new, but I want to convert to reference for further usage other than using pointer. Currently I am using this line Foo& rf = *f; to convert explicitly, it seems a bit silly. Any better and more elegant ways to create a reference variable and referring a new created instance?
Here are some code to show what I am doing,
class Foo{
public:
Foo(){
}
void printValue() {
cout << "This is Foo object " << endl;
}
};
int main() {
Foo* f = new Foo();
Foo& rf = *f;
rf.printValue();
f -> printValue();
}
You can write this:
Foo* foo = new Foo();
Foo& fooRef = *foo;
in one line:
Foo& fooRef = *new Foo();
But, be aware, you should delete your allocated memory later anyway:
delete &fooRef;
I do not suggest you write code in this way, to avoid memory leaks. Look into this answer for further details. Choose smart pointers or containers when it possible.
... convert to reference for further usage other than using pointer.
I prefer references (and avoid pointers) deep in my code. Mostly because a nullptr can have special meaning (that a reference will not) that needs some thought to confirm, the next time I review the code.
My solution is to new the bigger-than-automatic-memory object to get a pointer at the appropriate level for lifetime. I then invoke the using methods or functions with the dereferenced pointer. This keeps the pointer (at the lifetime start, such as main) as is, and later still available for the delete.
// bigData used many places
void use1_of_Data (BigData_t& bigData, Small_t& sd) {
//... do something with data
}
void use2_of_Data (BigData_t& bigData, Small_t& sd) {
//... do something with data
}
//...
void use3_of_Data (BigData_t& bigData, Small_t& sd) {
//... do something with data
}
int main(int argc, char* argv[])
{
// ...
BigData_t* bd = new BigDta_t; // (sizeof(BigData_t) > autovar space)
Small_t sd;
{
assert(nullptr != bd);
// note - bd lasts the lifetime of program
use1_of_Data (*bd, sd);
use2_of_Data (*bd, sd);
//...
use3_of_Data (*bd, sd);
}
// what's new'd in main, is deleted in main
delete bd;
}
As others have said, if the Foo instance's non-heap contents aren't so large that the Foo instance itself needs to be allocated on the heap, it is better to just use the stack:
Foo foo;
foo.printValue();
However, if it does need to be allocated on the heap for some reason, then it's dangerous to hold the only reference to it in an ordinary pointer, since if an exception gets thrown by any code, it will never be deallocated. In fact, most modern C++ guidelines advise not using ordinary pointers to own data for this reason:
Foo * fooPtr = new Foo();
doSomething(); // If an exception is thrown here, the Foo never gets deallocated!
Foo& foo = *fooPtr;
foo.printValue(); // If printValue throws an exception, the Foo never gets deallocated!
delete foo;
If you aren't familiar with this sort of problem, I suggest googling RAII ("Resource Acquisition Is Initialization") which is an crucial concept to understand when programming in C++.
An easy way to implement RAII in a case like this is through use of a smart pointer (std::shared_ptr or std::unique_ptr).
An extra reference variable can still be helpful to avoid having to use the arrow operator to call functions on the smartpointer. I disagree with some other answerers who don't see value in also binding a local reference to a value already held in a local pointer. I prefer to use references whenever possible, since when I use a reference, I can be sure that the reference isn't null (references should always refer to actual objects), while when I use a pointer (even a smart pointer) I must always be careful that my code correctly handles the case where the pointer is null. When the pointer initialization occurs close to the pointer's use, this may not be a big deal, but when they are separated, it can become hard to trace through the code to be sure the pointer can't be null. A reference makes this self-documenting.
I think that it is often useful to first ensure that a pointer or smart pointer value can't be null, and then to bind a local reference to the pointed-to value, since I can then use the reference freely without having to worry at each use about the possibility of it being null:
std::unique_ptr<Foo> fooPtr = std::make_unique<Foo>(/* Foo constructor args go here */);
doSomething(); // Now if an exception thrown here, Foo gets deallocated.
Foo& foo = *fooPtr; // We know the pointer is not null here (it just
// got returned from make_unique which
// didn't throw a bad_alloc exception) so it's
// safe to bind a reference to it here.
// Also, this reference has lifetime less than the
// smart pointer, so will never outlive it.
// .. many lines of code later ..
foo.printValue(); // No need to worry about null here.
// If exception thrown here, the unwinding of the stack
// causes fooPtr to deallocate Foo.
// No need to call delete here.
// fooPtr will automatically deallocate Foo when it goes out of scope.
If we speak about elegance, may I suggest you to use a shared_ptr?
#include <iostream>
#include <memory>
using namespace std;
class Foo{
public:
Foo(){
}
void printValue() {
cout << "This is Foo object " << endl;
}
};
int main(int argc, char *argv[])
{
Foo* f = new Foo();
std::shared_ptr<Foo> mySharedPtr(f);
f->printValue();
mySharedPtr.get()->printValue();
return 0;
}
In the following code I have been meticulous in the following of the standard's words (plus in the light of the wording of P0137) on object lifetimes.
Note that all memory allocation is through suitably-aligned storage of type unsigned char, as per P0137.
Note also that Foo is a POD, with a trivial constructor.
Questions:
A. If I have misunderstood the standard, and there is any UB here, please kindly point it out (or alternatively confirm that there is no UB)
B. Are the initialisations at A, B, C, D, E, F strictly necessary in light of the fact that the construction is trivial, and performs no actual initialisation. If so, please indicate which part of the standard contradicts or clarifies [object.lifetime] in this regard.
code:
#include <memory>
// a POD with trivial constructor
struct Foo
{
int x;
};
struct destroy1
{
void operator()(Foo* p)
{
// RAII to guarantee correct destruction order
auto memory = std::unique_ptr<unsigned char[]>(reinterpret_cast<unsigned char*>(p));
p->~Foo(); // A
}
};
std::unique_ptr<Foo, destroy1> create1()
{
// RAII to guarantee correct exception handling
auto p = std::make_unique<unsigned char[]>(sizeof(Foo));
auto pCandidate = reinterpret_cast<Foo*>(p.get());
new (pCandidate) Foo(); // B
return std::unique_ptr<Foo, destroy1>(reinterpret_cast<Foo*>(p.release()),
destroy1());
}
struct call_free
{
void operator()(void *p) const { std::free(p); }
};
using malloc_ptr = std::unique_ptr<unsigned char, call_free>;
struct destroy2
{
void operator()(Foo *pfoo) const {
// RAII to guarantee correct destruction order
auto memory = malloc_ptr(reinterpret_cast<unsigned char*>(pfoo));
pfoo->~Foo(); // C
}
};
std::unique_ptr<Foo, destroy2> create2()
{
// RAII to guarantee correct exception handling
auto p = malloc_ptr(reinterpret_cast<unsigned char*>(std::malloc(sizeof(Foo))));
auto pCandidate = reinterpret_cast<Foo*>(p.get());
new (pCandidate) Foo(); // D
return std::unique_ptr<Foo, destroy2>(reinterpret_cast<Foo*>(p.release()),
destroy2());
}
struct nodelete {
void operator()(Foo * p) {
p->~Foo(); // E
}
};
std::shared_ptr<Foo> provide()
{
alignas(Foo) static unsigned char storage[sizeof(Foo)];
auto make = [] {
auto p = reinterpret_cast<Foo*>(storage);
new (p) Foo (); // F
return std::shared_ptr<Foo>(p, nodelete());
};
static std::shared_ptr<Foo> pCandidate = make();
return pCandidate;
}
int main()
{
auto foo1 = create1();
auto foo2 = create2();
auto foo3 = provide();
foo1->x = 1;
foo2->x = 2;
foo3->x = 3;
}
On create1
std::unique_ptr<Foo, destroy1>(reinterpret_cast<Foo*>(p.release()), destroy1());
This doesn't work, because you're using the wrong pointer.
p.release() thinks it points to an unsigned char[]. However, that's not the object you want to point to. What you want to point to is the object that lives inside this array, the Foo you've created.
So you are now subject to [basic.life]/8. The gist of that is that you can only use the previous pointer as a pointer to the new object if they are of the same type. Which they're not in your case.
Now, I could tell you to launder the pointer, but the more reasonable way to handle this is to just store the pointer returned by the placement-new call:
auto p = std::make_unique<unsigned char[]>(sizeof(Foo));
auto ret = std::unique_ptr<Foo, destroy1>(new(p.get()) Foo(), destroy1());
p.release();
return ret;
That pointer will always be correct.
Your use of of placement-new is not optional. [intro.object]/1 tells us:
An object is created by a definition (3.1), by a new-expression (5.3.4), when implicitly changing the active member of a union (9.3), or when a temporary object is created (4.4, 12.2).
When you allocate an unsigned char[], that's the object you have created in that storage. You cannot simply pretend that it is a Foo, just because Foo is an aggregate. [intro.object]/1 doesn't allow that. You must explicitly create that object via one of the mechanisms listed above. Since you can't use a definition, union member activation, or temporary objects with arbitrary memory buffers to create objects from existing storage, the only recourse you have to create objects is a new-expression.
Specifically, placement-new.
As for delete1, you do need a custom deleter, since the default deleter will call delete on the Foo pointer. Your code is as follows:
auto memory = std::unique_ptr<unsigned char[]>(reinterpret_cast<unsigned char*>(p));
p->~Foo();
unsigned char[] has some special logic to it, in terms of how it behaves when objects are allocated in their storage, thanks to [intro.object]/3-4. If the object entirely overlays the storage of the unsigned char[], then it functions as if the object were allocated within the array. That means that the unsigned char[] is still technically there; it has not destroy the byte array.
As such, you can still delete the byte array, which your code here does.
On create2
This is also wrong, due to further violations of [basic.life]/8. A fixed version would be similar to the above:
auto p = malloc_ptr(reinterpret_cast<unsigned char*>(std::malloc(sizeof(Foo))));
auto ret std::unique_ptr<Foo, destroy2>(new(p.get()) Foo(), destroy2());
p.release();
return ret;
Unlike new-expressions, malloc never creates an object via [intro.object]/1; it only acquires storage. As such, placement-new is again required.
Similarly, free just releases memory; it doesn't deal with objects. So your delete2 is essentially fine (though the use of malloc_ptr there makes it needlessly confusing).
On provide
This has the same [basic.life]/8 problems that the rest of your examples have:
alignas(Foo) static unsigned char storage[sizeof(Foo)];
static auto pCandidate = std::shared_ptr<Foo>(new(storage) Foo(), nodelete());
return pCandidate;
But other than that, it's fine (so long as you don't break it elsewhere). Why? That's complex.
[basic.start.term]/1 tells us that static objects are destroyed in the reverse order of their initialization. And [stmt.decl]/4 tells us that block-scoped static objects are initialized in the order they are encountered in a function.
Therefore, we know that pCandidate will be destroyed before storage. So long as you don't keep a copy of that shared_ptr in a static variable, or otherwise fail to destroy/reset all such shared objects before termination, you should be fine.
That all being said, using blocks of unsigned char is really pre-C++11. We have std::aligned_storage and std::aligned_union now. Use them.
If you take seriously Core Issue 1776 and the never voted for idea that "that malloc alone is not sufficient to create an object", then you have to take seriously these ideas:
unions were not usable without UB in C++ until quite recently, as the lifetime of their members was not defined
string literals cannot be examined, as their lifetime is never started
and many other deeper more difficult controversies and contradictions, like what is a lvalue, an object, is lifetime a property of a preexisting object (that exists outside it's life), etc.
Yet I don't see people taking at least the two bullet points seriously. Why would the claim in the DR be taken seriously then?
"Core Issue 1776: Replacement of class objects containing reference members" is based on an obvious and serious interpretation error, and as such should be dismissed. The error is here:
Drafting note: this maintains the status quo that malloc alone is not
sufficient to create an object
This goes against the status quo that "malloc alone" is indeed sufficient to create an object, as malloc returns suitably aligned storage, which is and has always been sufficient to create an object.
A core issue is not the standard. It is an opinion about the standard. That opinion is in error.
Oh damn it I'm so stupid :-(,I could just use a bool array to reach the purpose
For example,I recieved a pointer p_class;
So how do I check if p_class points to a instantiated class?
I mean,even if the class was not been instantiated,every function of the class can still be called;and if I tried to access a variable in the class,I may access some illegal address and the program will crash
Well,I'm trying to write a network lib.
Since there are many protocols the lib have to support,
the_lib
{
public:
int selectProtocol(prtcl/*an enum*/ p)
{
switch(p)
{
case tcp:
t=new tcp;
....
}
}
int setTCP(opt,para)
{
switch(opt)
{
case csum:
t->setcsum(para)
break;
....
}
int setUDP(opt,para);
....
private:
TCP *t=0;
UDP *u=0;
...
}
Thus if the user select UDP at first but call setTCP, I have to determine whether to actually call the function in class TCP or not
0. The best thing to do? Don't use pointers.
MyClass instance;
instance.do_something(); // guaranteed to be safe to call
But if you need to refer to some object, then use references! In a well-formed piece of code, references are guaranteed to be pointing to some object, and thus any method you wish to call are guaranteed safe to be called.
But in those cases where you really need to use pointers, then:
1. Don't use raw pointers. Use smart pointers.
std::unique_ptr is almost always the best smart pointer for most of your cases. If you need shared semantics, then use std::shared_ptr. But remember: always prefer std::unique_ptr.
The good thing with most smart pointers is that they already do some default initialization for you when they are constructed without being initialized. Mostly, they set their internal pointer representation to nullptr.
2. Don't need ownership of an object? Just want to keep a reference but want to be able to set nullptr?
Use boost::optional<T&>. boost::optional has a specialization for references whose interface is very much like that of a pointer, but only much safer, as it does the same initialization technique as those of smart pointers.
3. Really need to use raw pointers for some unimaginable reason? Then always set it to nullptr when it's not meant to point to some object.
MyClass* p_instance = nullptr;
// Use p_instance, perhaps assign to it
p_instance = nullptr; // You don't need to use the pointed-to object
The gist of the above three techniques is this: because a pointer with a value of nullptr does not point to some valid object, then you can use it to check whether the pointer points to a valid object or not.
In this way your code can check if it's not initialized (p_instance == nullptr) or not (p_instance != nullptr). Also, the use of nullptr increase your chances of getting a runtime error when doing something on an invalid object, though the behavior is very much implementation dependent.
The general pattern for checking and using a pointer would be:
if(ptr) {
ptr->do_something();
}
But what if you really, really need to call do_something()? Then we are back to rule zero. :)
You can solve your problem by not using a bare pointer, and using a smart pointer instead. Both std::unique_ptr<> and std::shared_ptr<> have bool conversion operators that allow you to test if the pointer is valid or not.
class Foo { /* ... */ };
void foo (const std::unique_ptr<Foo> &p) {
if (!p) { /* ... */ }
}
void foo (const std::shared_ptr<Foo> &p) {
if (!p) { /* ... */ }
}
std::unique_ptr<Foo> p(new Foo);
std::shared_ptr<Foo> q = std::make_shared<Foo>();
If you are not performing dynamic allocation, then avoid pointers, and pass your object around to functions that take references.
void foo (const Foo &f) {
//...
}
My background is in more managed languages (C#, python) but I am becoming more experienced in C/C++. I am familiar with why the selection by reference (.) and selection through pointer operation (->) operators are different. In all cases I have encountered, if you use the incorrect one, it will result in a compile error. If that is the case, they why were they not made into one operator? Is there a case where using either on the same object results in different, meaningful and useful results?
This question inspired by this answer:
Is this right way to call a function in c++?
In C++ you can overload the ->-operator, which is used in pretty much all smart pointer implementations. However, some of those also have their own methods, i.e. to release a reference.
struct test {
int x;
};
std::shared_ptr<int> ptr(new test);
// Write to member x of the allocated object
ptr->x = 3;
// Reset the shared pointer to point to a different object.
// If there are no further shared_ptrs pointing to the previously allocated one,
// it is deleted.
ptr.reset(new test)
Additionally, it would be quite messy for the compiler to resolve operator-. for something like multiple-level pointers, i.e. test*** ptr. With your logic, ptr.x, (*ptr).x, (**ptr).x and (***ptr).x would all be the same.
You cannot apply -> to a reference to a basic type and you cannot apply . to a pointer, but you can apply both to a user-defined type and they will have different meanings. The simplest example is a smart pointer, like std::shared_ptr:
struct A { int x; };
std::shared_ptr<A> p(new A);
p->x = 10;
p.reset();
Is there a case where element selection by reference and element selection through pointer operation are both valid?
Since you can overload operator->() in C++, you can actually arrive at situations where you can use -> and . interchangeably on the same object. You can even engineer things so that you get a different result, as per this example:
#include <iostream>
struct Bar
{
void hello() const { std::cout << "Bar!!!\n"; }
};
struct FooBar
{
Bar bar;
void hello() const { std::cout << "FooBar!!!\n"; }
const Bar* operator->() const {return &bar; }
};
int main()
{
FooBar fb;
fb->hello();
fb.hello();
}
Of course, in real code you would never do something as crazy as this (although I have seen this kind of thing in "production" code).
the short answer would be a smart pointer
you can access the smart pointer class arguments using the "." (if you make your own smart pointer class you can extract from there for instance the current reference count) while you would use the "->" operator to access whatever is being stored using the smart pointer.
Couldn't figure out how to word the question accurately, so here's an example:
Given this function prototype:
void Foo(myClass* bar);
I want to prevent this usage:
Foo(new myClass());
and instead require a previously created object:
myClass* bar = NULL;
bar = new myClass();
Foo(bar);
or
myClass bar;
Foo(&bar);
Thanks.
EDIT
Here's a clarified example:
void Mouse::SetImage(BITMAP* image, int focusX, int focusY) {
if(_image) {
set_mouse_sprite(NULL);
set_mouse_sprite_focus(0, 0);
show_mouse(NULL);
destroy_bitmap(_image);
_image = NULL;
}
if(image) {
_image = create_bitmap(image->w, image->h);
clear_bitmap(_image);
blit(image, _image, 0, 0, 0, 0, image->w, image->h);
}
if(image == NULL) {
focusX = 0;
focusY = 0;
}
_focusX = focusX;
_focusY = focusY;
_dirtyImage = true;
}
Whatever image the user passes in gets copied to the object's image.
If I deallocate the passed in image after copying it and the image is used elsewhere in the program it will crash the program with an access violation.
If they allocate the storage in-line and I don't deallocated it, a memory leak occurs. The problem is compounded if they call the SetImage method multiple times over the course of the running program.
Comments about using alternative libraries or on the Allegro Library itself will be ignored, I already know it's horrible. I don't have a choice.
Your design needs to make a choice. Either take ownership and delete it, or don't take ownership. Either way, it's up to the user to know how to use your function. They either need to know that your function will destroy the image (and maybe pass their own copy as needed), or they need to be smart enough to manage their own resources.
Typically, you don't want to steal ownership away just to delete it. So I would not delete anything. If someone is silly enough to lose the ability to delete the image they pass, that's not this functions problem. In other words, you should try to protect against Murphy, but forget about protecting against Machiavelli.
That said, raw pointer use is bad! Poor C++ code is marked by manual resource management and resource issues. You should have a wrapper around an image, that will delete the image in the destructor. That way you can never leak, even if an exception is thrown. Provide it with a reset() method which discards it's old image resource and gets a new one.
It sounds like you want shared ownership, so you'll want a reference counted resource wrapper. The issue is then solved: if someone does an "inline" allocation, it'll be put into the shared pointer and then deleted automatically when it's done. (And even better is to have an explicit constructor so someone has to know they'll be sharing the resource.)
This is done in a smart pointer called shared_ptr. Boost has one, TR1 has one, and C++0x has one. Just give it a custom deleted (one that frees the image), and you never worry about resource management again.
This should be done with all resources. The concept here is Scoped-bound Resource Management (SBRM); that a resource is managed automatically by taking advantage of the lifetime rules of automatic (stack) variables. It's known alos as it's original but uglier name Resource-Acquisition Is Initialization (RAII). Do some research into this area and you'll find your code is easier and cleaner.
It cannot be done without changing the type of the parameter. You could change it to:
void Foo(myClass*& bar);
Because a non-const reference can only be bound to an lvalue:
void foo(int*&);
int main(void)
{
int *i = 0;
int j;
foo(i); // well-formed
foo(&j); // ill-formed
foo(new int); // ill-formed
}
However, this disallows taking the address of an lvalue. You can of course do the simple:
int main(void)
{
int j;
int* pj = &j;
foo(pj); // well-formed
}
And it works. But I don't know why you'd want to do any of this.
The above solution would allow you to modify the argument (because it's a reference). If you wanted to enforce const within the function, you could make a utility like this:
template <typename T>
class require_lvalue
{
public:
require_lvalue(T& pX) :
mX(pX)
{}
const T& get(void) const
{
return mX;
}
operator const T&(void) const
{
return get();
}
private:
// non-copy-assignable
require_lvalue& operator=(const require_lvalue&);
const T& mX;
};
void foo(require_lvalue<int*>);
Same result, except you have a const-reference within the function.
Note that MSVC has a bug, and accepts this:
foo(new int);
in both cases, even though it shouldn't. (It does not accept new int(), however.)
It's impossible to have such a distinction of usage. And in all the cases it's a valid parameter. I really can't understand why you need this...
So don't use pointers... use (lvalue) references:
void Foo(myClass& bar);
Doesn't this solve your task?
But I anyway recommend something like std::auto_ptr for such cases.
#include <iostream>
void test(int *& ptr)
{
std::cout << *ptr << std::endl;
}
int main()
{
/* NEXT LINE WILL FAIL */
// test(new int(5));
int *b = new int(5);
test(b);
delete b;
return 0;
}
C or C++ does not give you the luxury of determining where the memory was allocated, that come into your function's parameters. If you want better safety then program in .NET.
If you want to make it safer, than just completely change your function signature to accept an auto pointer. that way the semantics become crystal clear, and there should be no confusion as to whom or what owns the memory.