the program is about Blob<T>, where shared_ptr<std::vector<T> > as its data members.
be noted that the real problem here is about shared_ptr of my own version (simple one) but
atleast (should) worked with the Blob<T>, which is the std::shared_ptr did, but not with mine.

Error Msg

the error msg above is produced through object that's being constructed by initializer list.

if the object being constructed through default constructor then being append by push_back() function.
the program compile but crashed. just after the shared_ptr::operator*() executed.yet I still unable to
figure out the problems.

T& operator*() const { return *p; }
T* operator->() const { return & this->operator*(); }

and the make_shared function: (probably another factor).

template <class T, class... Args>
shared_ptr<T> make_shared(Args&&... args)
{
    return shared_ptr<T>(std::forward<Args>(args)...);
}

We need more detail. You say you are using a custom version of shared-ptr, and the error seems to be in that custom class. So, we need to see that code, otherwise there is really no way to tell where the error might come from.

Ok, about the error, it's very simple, I should have caught it earlier... You need to using new to allocate an object to pass to the shared-ptr:

return shared_ptr<T>(new T(std::forward<Args>(args)...));

in your make-shared function.

But looking at your shared-ptr class, there are obvious problems:

template <typename T> 
class shared_ptr {
  public:
    shared_ptr() = default;
    shared_ptr(T* point): p(point) { ++count; }
    shared_ptr(T* point, std::function<void(T*)> rem):
        p(point), del(rem) { ++count; }
    shared_ptr(const shared_ptr<T>& val):
        p(val.p), count(val.count), del(val.del) { ++count; }

    T& operator*() const { return *p; }
    T* operator->() const { return & this->operator*(); }
    std::size_t use_count() { return count; }

    void deleting()
        { del ? del(p) : delete p; }
    ~shared_ptr() { if(count) deleting(); else --count;}
  private:
    T *p = nullptr;
    std::size_t count = 0;
    std::function<void(T*)> del;
};

Here is a few problems that immediately pop out:

  1. No copy-assignment operator.
  2. No move-constructor and move-assignment operators.
  3. Single-parameter constructor not marked with explicit.
  4. The test if(count) should be if(count == 1) (or, use if(--count == 0)).
  5. The reference count needs to be a shared state between all shared-pointers that point to the same object. Just consider this situation ("sp" for shared_ptr<T>): sp p1(new T()); sp p2 = p1; sp p3 = p1;, which will result in p1 having a count of 1, p2 and p3 both having a count of 2, and the object will be destroyed as soon as p1 is destroyed, regardless of the situation, i.e., there is, in effect, no reference counting.
  6. You have a lot of overhead having to copy around the deleter functor, especially since std::function uses type-erasure, which is very convenient but copy operations are expensive.
  7. The deleting() function should not be public, obviously.
  8. There are obviously a ton of functions missing to make it truly a drop-in replacement for the standard / Boost shared-pointer class.

I hope that gives you some constructive grounds on which to improve your implementation. Implementing a shared-pointer class correctly is a very tricky task, especially if you want "advanced" features such as thread-safety, exception-safety, cross-modular safety, binary compatibility, etc..

tbh I don't even bother about its design before building the code(if it has any :p), funny because the author expect me to write its implementation for the shared_ptr that's compatible with Blob<T> but then, after 30 question or so, the books told me to implement make_shared<T>().(Variadic template's subchapter)

(I actually skipped the question to be answered after I build the make_shared<T>() function)
I thought the author just want me to implement it just to test my basic template building skill then apply it to a designated container. Yet, you just make me realized that I still have bad habit and prediction skill, such as 3, 4, 5, and 7. 1,2 6, and 8 is intentional(too lazy, use anything as long as it is "working").

However, I still not able to figure out when to "draft" the design and where to stop. Always heard such quote "the more time spent on designing, the less time spent on coding", but in the end I always end up with the code become too different from the design itself(either incompatible type or technique). In the end, if no new algorithm needed to think of, I usually design & coding on the spot. (gotta spark a bad habit though :S)

another things is, it's amazing that you are debugging this code so fast (a commend for my another thread too), how did you do? The only way I use to "debug" is print out the value of certain object (that probably) affect the outcome. and it's impossible to do with shared_ptr, which ptr connect to it, how much pointer it hold. I can just output its counter's value but then as you said in 5, the counter not connected with each other, the info it give is misleading (as it did to me, I honestly thought it works, lel) thus, it's such a big failure.

Edited 2 Years Ago by Vasthor

doesn't if(--count) is equal to if(--count == 0)

No, they are exactly opposite. If you having any integer or pointer variable, call it a, then writing if( a ) is equivalent to writing if( a != 0 ), because any non-zero (or non-null) value converts to true, so, if(a) is true as long as a is not equal to zero.

I thought the author just want me to implement it just to test my basic template building skill then apply it to a designated container.

Or maybe the author just wanted you to discover the issues that you are discovering right now. If that's the case, then that author is smart, because the best way to learn is not to be told step-by-step how to do things, but to discover the issues and search for ways to solve them on your own.

Yet, you just make me realized that I still have bad habit and prediction skill, such as 3, 4, 5, and 7.

That's alright. Bad habits die hard, but the earlier you become aware of them, the better.

1,2 6, and 8 is intentional(too lazy, use anything as long as it is "working").

Well, 1 and 2 are not really optional. Not having those constructors / operators is a bug, and of the worst kind. The worst kind of bug is when it still is "working", or so it seems, but it is actually doing the wrong thing, and silently introducing problems in your code (such as double deletions) that will be very difficult to track down later. You have to be extra careful about these things if you want to avoid yourself a world of pain, that's why they are number 1 and 2 on the list, because (1) is a major bug, and (2) is a related but more minor bug. Look at the "Big Five" example.

lways heard such quote "the more time spent on designing, the less time spent on coding", but in the end I always end up with the code become too different from the design itself

I think you have to gain some better perspective on what is design and what is coding before you can really know where to stand on this. By its nature, the design process is much more high-level than the coding. You should not be, in general, designing the small coding details, you design the overall architecture or structure of the code, while the coding is about the details (such as resolving issues like 1-8 above). For example, with shared-pointer, the "design" part is figuring out that you want some smart-pointer, that holds a reference-count, that automatically deletes the pointer when the last shared-ptr is destroyed, that you might want it to be thread-safe and exception-safe, etc.. and the "coding" part is figuring out what data members you need in that class, what constructors / operators / helper functions you need to provide, and solving the issues. The expression that the more you desing the less you code is mostly about the fact that it is a lot easier to implement a good design, and a lot more permanent (don't have to re-write it), it does not mean that you have to design every detail of the code, it's still a high-level process.

I usually design & coding on the spot.

This is fine for most simple stuff, it's only when you do really complicated projects that you have to spend more time designing ahead of time.

it's amazing that you are debugging this code so fast (a commend for my another thread too), how did you do?

That just comes from years of practice. At this point, I pretty much have a C++ compiler built into my brain, and I know how to spot bugs because I pay attention to the things that I know, from experience, often contain bugs. Most of the issues I pointed out are things that I look out for all the time, because people always make mistakes like that, and I've made them plenty of times in the past too. It's simple, you put a piece of code in front of me, and there is immediately a checklist of potential dangers or bugs that appears in my brain, and then, I just go down that list, and I quickly find most bugs. That's just a reflex that you develop over time.

It's normal that you cannot do this yet, just go step by step.

This question has already been answered. Start a new discussion instead.