#std::uniniitialized_copy example UB?

60 messages · Page 1 of 1 (latest)

short wind
#

isn't this example UB? std::string is not an implicit lifetime type I reckon:

#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
 
int main()
{
    const char *v[] = {"This", "is", "an", "example"};
 
    auto sz = std::size(v);
 
    if (void *pbuf = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz))
    {
        try
        {
            auto first = static_cast<std::string*>(pbuf);
            auto last = std::uninitialized_copy(std::begin(v), std::end(v), first);
 
            for (auto it = first; it != last; ++it)
                std::cout << *it << '_';
            std::cout << '\n';
 
            std::destroy(first, last);
        }
        catch (...) {}
        std::free(pbuf);
    }
}

from https://en.cppreference.com/w/cpp/memory/uninitialized_copy

#

(please ping btw, thanks)

hallow raft
#

@short wind well the question is what part do you think would require implicit lifetime properties
The call to uninitialized copy in and of itself is fine, because the point of uninitialized copy is to create new objects in a certain region of storage
Those new objects need not have implicit lifetime types

short wind
hallow raft
#

It's used as if it was properly allocated and aligned to be able to store a string

#

If it was used as if it was a string, you would just copy

#

You wouldn't uninitialize copy

#

Uninitialize copy starts lifetime on its own, that's the point

short wind
#

ok, you're right, it's a pointer and then uninitialized copy does placement new with value_type inside

hallow raft
#

It would be UB to use uninitialize copy if there already were objects

heady imp
#

most uses of std::uninitialized_copyare perfectly valid

#

though you may leak resources of you overwrite things

heady imp
#

also notice how the cppreference article says that std::uninitialized_copy uses placement new, and also see [uninitialized.copy] p2

#

I guess it could be constexpr too, if someone bothered defining it in terms of std::construct_at

#

or with the C++26 proposal for casting to/from void*, it could just be constexpr normally, I think

hallow raft
#

Transparently replaceable

#

Actually I think it is it isn't because transparent replaceability is not a type property, but a relationship between two objects, so my broken up sentence makes no sense

#

But the UB I was referring to was due to skipping the destructor which has side effects

#

And now I don't remember if that's outright UB or not

#

Ending an object's lifetime without invoking its destructor isn't outright UB even if the destructor does stuff, but resource leaking is probably some kind of UB-y thing

#

Is leaking memory not actually UB in standard-y terms? If you "just" leak you make it increasingly likely that future allocation fails with all the problems that will cause to your program, but I can't really think of a relevant clause that would make this outright UB

hallow raft
#

I'll just pretend that I meant UB: Unlimitedly Bad

heady imp
#

however, even this rule doesn't appear to exist anymore

#

the quoted paragraph there, I cannot find it in the working draft ...

hallow raft
#

It used to be in basic.life

#

Fairly sure

heady imp
#

yeah this is where it used to be

#

looks like they just dropped the rule in C++23, that depending in side effects is UB

#

the rest is still there

#

honestly that's a good thing, that was a dumb, unnecessary, and undiagnosable rule

#

when you don't call the destructor, you just don't call the destructor, simple as

#

nothin' UB 'bout that

hallow raft
#

There are plenty of rules that are undiagnosable

#

Not completely sure what the change achieves tbh

#

But skipping a destructor that you shouldn't skip is some kind of "bad"

#

Though I guess at the language level it doesn't achieve much to have that rule

heady imp
#

yeah

#

it's like saying it's UB if you forget to print a newline character at the end of the line with std::cout when you intended to print one

hallow raft
#

I guess that opens up relocation to remove that phrasing

heady imp
#

you can't even begin to diagnose that paragraph, not even with sanitizers

hallow raft
#

I need to reread the original

heady imp
#

it's unimplementable out of the box

hallow raft
#

Phrasing

#

Actually I need to reread the new phrasing as well, but I think the old one isn't compatible with trying to push relocation or whatever the name is, into the language

#

So http://eel.is/c++draft/basic.life#note-4 is basically "you generally don't want to do that" as per the old ruling/phrasing
But the new phrasing technically makes it legal to release/reuse the storage of an object after you've "relocated" that object

#

And you've basically entrusted the proper destruction call to the relocated object instance

#

I guess

#

Wonderful, I'll need to reread basic.life entirely soon

#

And see if you can actually do that

#

Then get bit by some clause elsewhere

heady imp
#

the UB was actually removed because it would be unreasonable to diagnose this in constant expressions

hallow raft
#

Right, UB has to be diagnosed there...