#Is there an easy way to make a shared_ptr depend on a different shared_ptr's lifetime?

1 messages · Page 1 of 1 (latest)

spiral ruin
#

assume I have the work function:

shared_ptr<T> workFunction(shared_ptr<S> *retainS)
{
    shared_ptr<I> i{createI(), freeI};
    shared_ptr<S> s{createS(i.get()), freeS};
    if (retainS)
    {
        *retainS = s;
    }
    shared_ptr<T> t{createT(s.get()), freeT};
    return t;
}

In this function retainS may optionally contain a pointer, adding another reference to the created S made in this function. The S must always be free'd before I so there needs to be a way to tell the I object that it's lifetime is tied to S or the code won't work as is.

hard wraithBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

sly arrow
#

sounds like shared_ptr is not what you want

spiral ruin
#

maybe not, but it would be nice to have a fire and forget option

sly arrow
#

shared_ptr is not fire and forget either. there's no such thing as a fire and forget option.

#

some people just like to think so. they are badly mistaken tho.

spiral ruin
#

I mean its fairly close anyways

#

and even if its not close its a pretty bad tool if you cant use it that way

sly arrow
#

it really isn't. it just delays the inevitable. usually until it's too late.

#

shared_ptr is 99% of the time the wrong tool yes.

#

most people just don't understand that.

spiral ruin
#

my other option has just been allowng the memory to leak because its image data I loaded from a file, so I mean thats also not great

sly arrow
#

the problem is that shared_ptr usually lets you pretend that you don't need to think about these issues for long enough that you end up painting yourself into a corner it's incredibly painful to crawl out of.

#

but i guess the only cure for the shared_ptr craze is having to go through that at least once ^^

spiral ruin
#

I am just going to go back to using a memory arena. Its literally fire and forget to allocate a sizeable chunk of memory and delete it into oblivion when I am done

sly arrow
#

i don't know what it is you're doing so i'm afraid it's pretty much impossible to make any meaningful suggestions

#

all i can say is that shared_ptr can't do this and this sounds like a thing you shouldn't be in need of doing anyways.

spiral ruin
#

shared_ptr is a pretty annoying api to be honest but I don't see how its 99% the wrong tool to be honest.

#

except in this case I see its definitely not an option

#

without massive c++ copium

cosmic pasture
#

The use-case of std::shared_ptr is when you give a resource to 2 threads and after both threads are done with the resource it needs to be cleaned up, but you don't know where to do that because you cannot know which thread will finish first.

#

If you don't have threads there is no proper reason to use std::shared_ptr. It's not a Java-like garbage collector.

spiral ruin
#

that seems like a convenience situation as well

cosmic pasture
#

I don't properly understand your example. There is a way to make std::shared_ptr point to one thing while reference-counting another thing. It's when you have for example a linked list that uses a std::shared_ptr<Node> which is ```cpp
struct Node {
Node *next;
T t;
};

and you want to return a `std::shared_ptr<T>` which keeps the `Node` alive that the `T` lives in. You don't want to leak `Node` itself because it's an implementation detail of the list.

I can't tell if this is what you're asking.
#

On second read it seems like you want std::shared_ptr to ref-count 2 things. You could make a struct with 2 std::shared_ptrs inside and use the above to point to one of the members, but it seems like a horrible design that you will regret later.

spiral ruin
#

I guess if you want to see my use case. I was just loading image from a texture from something I was working with SDL. I needed to improve performance somewhat so I cached the surface data to construct larger textures so I make less draw calls. The SDL docs say that the surface needs to be free'd before the pixel data and thus the destruction can potentially go out of order. Anyways thanks for the feedback.

shared_ptr<SDL_Texture>
createTextureFromFile(
    string fname,
    SDL_Renderer *renderer,
    i32 *width,
    i32 *height,
    shared_ptr<SDL_Surface> *resultSurface
) {
    Assert(renderer);
    Assert(width);
    Assert(height);
    i32 components;
    stbi_uc *pixelData = stbi_load(fname.c_str(), width, height, &components, 0);
    Assert(pixelData);
    Assert(*width);
    Assert(*height);
    shared_ptr<SDL_Surface> tempSurface{SDL_CreateRGBSurfaceFrom(
        pixelData,
        *width, *height,
        components * 8,
        *width * components,
        255,
        255 << 8,
        255 << 16,
        255 << 24),
        SDL_FreeSurface};
    
    Assert(tempSurface);

    if (resultSurface)
    {
        *resultSurface = tempSurface;
    }

    shared_ptr<SDL_Texture> texture(
        SDL_CreateTextureFromSurface(renderer, tempSurface.get()), SDL_DestroyTexture);
    Assert(texture);

    return texture;
}```
cosmic pasture
#

Sounds like you can use the above.

sly arrow
#

you usually know the scope during which your surfaces are alive tho. can't you just allocate the data in a parent scope and now no surface will ever outlive the data and done, no need for any shared_ptr anywhere whatsoever?

spiral ruin
#

I mean yeah probably. Both of my braincells were working overtime when I architected this thing and I was just experimenting with the latest and greatest c++ standards because reasons. I rarely do that though.

sly arrow
#

shared_ptr is generally a niche feature with very niche applications (if any tbh, personally, i haven't found an application yet where it would have been satisfied that shared_ptr is actually a good solution).

spiral ruin
#

yeah well when in rome shit like the romans. or something like that?

sly arrow
#

dunno, some shared_ptr fest like this thing up there is certainly not what i'd consider idiomatic C++ ^^

#

i'm not sure where you'd get the idea that that's the typical or even recommended way of doing things in C++

#

as a general rule of thumb: if you're reaching for shared_ptr, you're probably doing something wrong. and if you're passing a pointer to a shared_ptr, you're pretty much guaranteed doing smth wrong ^^

cosmic pasture
spiral ruin
#

well passing a pointer to a shared_ptr isn't really a problem though, its just an optional parameter

cosmic pasture
#

Bonus points if you can find a better name than "George".

sly arrow
#

what i'm not sure i understand is: are there ever going to be multiple surfaces that share the same data in this system of yours?

#

because if not, why not just keep the data with the surface?

spiral ruin
#

Now I cant even remember. I was taking each surface and combining it into a large texture on the fly as I zoom around a tilemap to save on draw calls. Otherwise I am drawing thousands of times and SDL is rather slow to call SDL_RenderCopy

#

so no I don't think so each surface is just the uncompressed image I believe

sly arrow
sly arrow
spiral ruin
#

yeah and in my infinite OOP design wisdom I had a TileChunk class which got both of those things out from that optional parameter I was talking about lol

#

the resultSurface parameter

#

pretty sure this is just my terrible API design. I doubt I need some crazy shared_ptr magic to make this work.

sly arrow
#

tbf, this is mostly just an annoying quirk of SDL anyways it seems…

spiral ruin
#

well I don't want to blit things myself and I want to make this cross-platform

#

otherwise I would use direct2d

#

SDL is not that bad..

#

well I guess I haven't tried many other 2d api's I should give some other things a try

hard wraithBOT
#

@spiral ruin Has your question been resolved? If so, run !solved :)

spiral ruin
#

!solved