Cannot Invoke Initializer for Type 'Sqlite3_Destructor_Type'

Accessing an SQLite Database in Swift

While you should probably use one of the many SQLite wrappers, if you wanted to know how to call the SQLite library yourself, you would:

  1. Configure your Swift project to handle SQLite C calls. If using Xcode 9 or later, you can simply do:

    import SQLite3
  2. Create/open database.

    let fileURL = try! FileManager.default
    .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    .appendingPathComponent("test.sqlite")

    // open database

    var db: OpaquePointer?
    guard sqlite3_open(fileURL.path, &db) == SQLITE_OK else {
    print("error opening database")
    sqlite3_close(db)
    db = nil
    return
    }

    Note, I know it seems weird to close the database upon failure to open, but the sqlite3_open documentation makes it explicit that we must do so to avoid leaking memory:

    Whether or not an error occurs when it is opened, resources associated with the database connection handle should be released by passing it to sqlite3_close() when it is no longer required.

  3. Use sqlite3_exec to perform SQL (e.g. create table).

    if sqlite3_exec(db, "create table if not exists test (id integer primary key autoincrement, name text)", nil, nil, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error creating table: \(errmsg)")
    }
  4. Use sqlite3_prepare_v2 to prepare SQL with ? placeholder to which we'll bind value.

    var statement: OpaquePointer?

    if sqlite3_prepare_v2(db, "insert into test (name) values (?)", -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing insert: \(errmsg)")
    }

    if sqlite3_bind_text(statement, 1, "foo", -1, SQLITE_TRANSIENT) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure binding foo: \(errmsg)")
    }

    if sqlite3_step(statement) != SQLITE_DONE {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure inserting foo: \(errmsg)")
    }

    Note, that uses the SQLITE_TRANSIENT constant which can be implemented as follows:

    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
  5. Reset SQL to insert another value. In this example, I'll insert a NULL value:

    if sqlite3_reset(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error resetting prepared statement: \(errmsg)")
    }

    if sqlite3_bind_null(statement, 1) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure binding null: \(errmsg)")
    }

    if sqlite3_step(statement) != SQLITE_DONE {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure inserting null: \(errmsg)")
    }
  6. Finalize prepared statement to recover memory associated with that prepared statement:

    if sqlite3_finalize(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error finalizing prepared statement: \(errmsg)")
    }

    statement = nil
  7. Prepare new statement for selecting values from table and loop through retrieving the values:

    if sqlite3_prepare_v2(db, "select id, name from test", -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing select: \(errmsg)")
    }

    while sqlite3_step(statement) == SQLITE_ROW {
    let id = sqlite3_column_int64(statement, 0)
    print("id = \(id); ", terminator: "")

    if let cString = sqlite3_column_text(statement, 1) {
    let name = String(cString: cString)
    print("name = \(name)")
    } else {
    print("name not found")
    }
    }

    if sqlite3_finalize(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error finalizing prepared statement: \(errmsg)")
    }

    statement = nil
  8. Close database:

    if sqlite3_close(db) != SQLITE_OK {
    print("error closing database")
    }

    db = nil

For Swift 2 and older versions of Xcode, see previous revisions of this answer.

C++: How to improve performance of custom class that will be copied often?

Ideally you'd have all the information necessary to setup Bar at the time Foo is constructed. The best solution would be something like:

class Foo { 
Bar b;
public:
Foo() : b() { ... };
Foo(const Foo& f) : b(f.a, f.b) { ... };
}

Read more about constructor initialization lists (which has no direct equivalent in Java.)

Using a pointer pb = new Bar(arg1, arg2) will actually most likely deteriorate your performance since heap allocation (which could involve, among other things, locking) can easily become more expensive than assigning a non-default constructed Bar to a default-constructed Bar (depending, of course, by how complex your Bar::operator= is.)

Default constructor in C

You can create initializer functions that take a pointer to a structure. This was common practice.

Also functions that create a struct and initialize it (like a factory) - so there is never a time where the struct is "uninitialized" in the "client" code. Of course - that assumes people follow the convention and use the "constructor"/factory...

horrible pseudo code with NO error checking on malloc or free

somestruct* somestruct_factory(/* per haps some initializer agrs? */)
{
malloc some stuff
fill in some stuff
return pointer to malloced stuff
}

void somestruct_destructor(somestruct*)
{
do cleanup stuff and also free pointer
free(somestruct);
}

Someone will probably come along and explain how some early C++ preprocessors/compilers worked to do this all in C.

Type trait to identify types that can be read/written in binary form

Given a 1st parameter of s, the read method:

Extracts characters and stores them into successive locations of the character array whose first element is pointed to by s

So your real question is: If I have initialized an object by writing a string of bytes to it's address, is it valid?

This is the concept of Value Representation. And the value representation of Trivially Copyable types is such that:

Copying the bytes occupied by the object in the storage is sufficient to produce another object with the same value

Thus you want to ensure that your object is Trivially Copyable this isn't per say a standard concept but it can be succinctly defined as:

  • Every copy constructor is Trivial or deleted
  • Every move constructor is Trivial or deleted
  • Every copy assignment operator is Trivial or deleted
  • Every move assignment operator is Trivial or deleted
  • At least one copy constructor, move constructor, copy assignment operator, or move assignment operator is non-deleted
  • Trivial non-deleted destructor

The spirit of the assertion that at least one Trivial initializer exists for the object boils down to these requirements of a Trivially Copyable type, it's non-static members, and any of it's base classes:

  1. It's given Trivial Initializer is, or behaves as, the corresponding default intializer
  2. It has no virtual methods
  3. It has no members of a volatile-qualified type

As far as the requirement of a Trivial destructor:

  • The destructor is not user-provided (meaning, it is either implicitly declared, or explicitly defined as defaulted on its first declaration)
  • The destructor is not virtual (that is, the base class destructor is not virtual)
  • All direct base classes have trivial destructors
  • All non-static data members of class type (or array of class type) have trivial destructors

Having fully defined what it means to be a Trivially Copyable type, it is impossible for a "type trait or concept" to determine whether all of these requirements are met in all cases, for example: A type that defines a Trivial Initializer with a signature that matches the default initializer may or may not be Trivially Copyable contingent on the code which initializes the type in that initializers body; For such a type, the only way to determine if it's Trivially Copyable is human inspection of the initializer. If however you are willing to tighten the requirements to what is detectable, is_trivially_copyable will guarantee that your type is Trivially Copyable.



Related Topics



Leave a reply



Submit