Binary Search Tree implementation using smart pointers
please do not using namespace std;
why has Bst::findmin no prefix _?
why do you use std::shared_ptr&lt;&gt; at all? std::shared_ptr is ment to represent shared ownership. This makes no sense for tree nodes, you're not going to have two trees with the same nodes. std::unique_ptr&lt;&gt; is a better candidate.
it is generally good to separate the data structure from its serialization. Make print a separate function and also handle the member printing outside of the class. 




Edit
As you had trouble getting the unique_ptr running, here's what works for me.

Modify the node to use unique_ptr:

struct node
{
    int val;
    std::unique_ptr&lt;node&gt; left;
    std::unique_ptr&lt;node&gt; right;

    // c'tor left out
};


Also, use a unique_ptr for root. You'll receive heavy compiler complaints, 
because a unique_ptr cannot be simply copied (one of the instances must go invalid, as it's unique). I suggest altering the private functions:

void _insert(std::unique_ptr&lt;node&gt;&amp; curr, int val);
void _del(std::unique_ptr&lt;node&gt;&amp; curr, int val);


Sample implementation for _insert:

void Bst::_insert(std::unique_ptr&lt;node&gt;&amp; curr, int val)
{
    if (!curr)
    {
       curr = std::make_unique&lt;node&gt;(val);
       return;
    }

    if (val &lt; curr-&gt;val)
    {
        _insert(curr-&gt;left, val);
    }
    else
    {
        _insert(curr-&gt;right, val);
    }
}


Your public insert method would be something like:

void insert(int val)
{ 
    _insert(root, val);
}


Also: add a find function to see if an element is in the tree. Use the find function to write some simple tests. You may rename del to erase to be closer at the standard naming. 



Edit 2 Separate output from data storage:

A friend function is relatively inflexible, as you cannot easily exchange the printing algorithm. You may implement iterators (hard) or provide a traverse function. I'd go for the second approach, as you already have the algorithm in _print: rename print to traverse and pass it a function pointer, then replace the output to std::cout by a call to the function pointer. 


class Bst
{
...
    // traverse with function pointer
    void traverse(void (*func)(int));
};

int main()
{
    Bst b;
    // insert data ...    

    b.traverse([](auto v){ std::cout &lt;&lt; v &lt;&lt; " "; });
    std::cout &lt;&lt; "\n";
}