C ++ smart pointers are confusing

I understand that the use of smart pointers is recommended in the C ++ domain. I have a simple program as shown below.

/* main.cpp */
#include <iostream>
#include <memory>
using namespace std;

/* SQLite */
#include "sqlite3.h"

int main(int argc, char** argv)
{
    // unique_ptr<sqlite3> db = nullptr; // Got error with this
    shared_ptr<sqlite3> db = nullptr;

    cout << "Database" << endl;
    return 0;
}

      

When compiling with the unique_ptr string, an error message appears:

error C2027: use of undefined type 'sqlite3'
 error C2338: can't delete an incomplete type

      

When compiled with a shared_ptr line, this is successful. From several questions and answers, my understanding is that unique_ptr should be preferred as I am not going to have resources to share objects. What's the best solution in this case? Use shared_ptr or fallback to the old approach with null pointers (new / delete)?

+3


source to share


3 answers


sqlite3

- opaque structure (very similar to FILE

from C). All you have is its declaration, not its definition. This means that you cannot use it std::unique_ptr

directly without a custom delete.



+4


source


The general approach is in @SomeProgrammerDudes answer (accept it). But for solving your problems, I am posting this.

You don't have to go back to the original new and delete. Not because it sqlite3

is opaque, or because of the overhead std::shared_ptr

. You are using, as pointed out by another answer std::unique_tr

.



The only difference is in how you set up the custom divider. For std::unique_ptr

this is part of the type definition, not a runtime parameter. Therefore, you need to do something like this:

struct sqlite3_deleter {
  void operator()(sqlite3* sql) {
    sqlite3_close_v2(sql);
  }
};

using unique_sqlite3 = std::unique_ptr<sqlite3, sqlite3_deleter>;

      

+5


source


#include <memory>
#include <stdexcept>

/* sqlite 3 interface */
struct sqlite3 {};
extern void sqlite3_close(sqlite3*);
extern int sqlite3_open(sqlite3**);

/* our boilerplate */
struct closer
{
    void operator()(sqlite3* p) const
    {
        sqlite3_close(p);
    }
};

using sqlite3_ptr = std::unique_ptr<sqlite3, closer>;

/* handy maker function */
sqlite3_ptr make_sqlite()
{
    sqlite3* buffer = nullptr;
    int err = sqlite3_open(&buffer);
    if (err) {
        throw std::runtime_error("failed to open sqlite");
    }
    return sqlite3_ptr(buffer);
}

int main()
{
    auto mysqlite = make_sqlite();
}

      

+1


source







All Articles