In short, placement new (or some scenarios involving unions) technically cause undefined behavior if you try to use the object after the call to placement new, since the pre-existing object there has had its lifetime expire. std::launder lets you use a pre-existing pointer to the memory at the same location to access the data there.
I may be misunderstanding, but this seems to directly contradict what the linked paper says:
> Note that std::launder() does not “white wash” the pointer for any further usage.
> The obvious question is, why don’t we simply fix the current memory model so that using data where placement new was called for implicitly always does launder?
no, it is consistent. Launder does not white wash its parameter, only its return pointer and any pointer returned by it. Same for placement new.
Correct, but only if the original (referenced) object is not const itself. Casting away constness to modify an object that was declared const is 100% UB.
I save the data of whether or not it's a copy into a flag variable, so my program knows when and when not to delete a const char* .
The alternative would be of course to create a two variables, one char* and one const char* , but that would double the memory needed, but only one type of variable would be used at a time.
class string {
union {
const char *referenced;
char *copied;
} data;
bool copied;
public:
string(const char *source, booly copy) {
if(copy) {
data.copied = strdup(source);
copied = true;
} else {
data.referenced = source;
copied = false;
}
}
operator const char *() const {
return copied ? data.copied : data.referenced;
}
~string() {
if(copied) {
free(data.copied);
}
}
};
No const_cast and no wasted memory and it's clear that you are storing two semantically different types.I would expect the conversion operator to optimize down to a noop since in all cases the returned address is equal to this.
I want the pointer (actually, that to what it's pointing to) to be referenced as const in all cases, except when I create a copy or delete that copy, in which case I then explicitly recast them as not-const. That's just two tiny exceptions in code I have to write anyways.
Such as it is, I would only consider a union of them if I'd actually need const/non-const 50/50 of the time, but my current use case is more like 98/2.
Apart from that, I'm guessing you're from a C++ background, as there are no classes in C? (and also, if you use C++, it's recommended to use "delete" instead of "free", since the latter is a C function)
EDIT: Actually, it's only one exception/re-cast, when I delete it, as no compiler would complain about saving a char* in a const char* data type.
how could it make that assumption ? there is nothing that prevents you to implement the function in fortran or even in raw assembly
Now, the tricky part is that const objects (i.e. objects declared as const) enjoy these optimization benefits, but the compiler usually cannot prove that a reference or pointer to const actually refers/points to a const object. Taking a const pointer to a non-const object, casting away the constness again and then modifying the object is totally legal.
Since the former case (objects declared const) is much rarer than the latter case (working on const object pointers/references) the compiler cannot often optimize based on const.
template<class T>
struct deep_const { const T value; };
template<class T>
const deep_const& freeze(const T&) { /* magic */ }
template<cass T>
const T & thaw(deep_const<T> const&) { /* more magic */ }
magic and more magic left as an exercise for the reader.edit: I do not think either GCC or clang take advantage of that though, so currently it is just a curiosity.
edit: missed actual const keywords /facepalm
[0] The Design and Evolution of C++