c++ - 我创建了一个库,想知道设计是否效率低下

标签 c++ c++11

在设计我的库时,我构造了很多对象,想知道这是否会导致它效率低下。

我创建了一个库来创建和运行查询。查询是一个类,它采用对 Bind 对象的 initializer_list 的右值引用。每个 Bind 都有一些值。

我认为这种设计效率低下,因为如果我们使用 const char*,每个 Bind 对象都将复制其值(字符串除外) .最重要的是,我们必须为每个值构建一个完整的 Bind 对象。然后我将所有 Bind 舍入到一个 initializer_list 并将它们移动到一个 vector 中,我不确定有多少开销.这是在 Query 对象中创建的,构建起来可能不会那么昂贵,并且只创建了一个 Query 对象。

查看代码片段底部的 main 函数可能就是您需要查看的全部内容。

class Database {
public:
    Database() = default;
    ~Database() = default;
    Result run(Query&& query);    
};

class Query {
public:
    Query(const char* query, std::initializer_list<Bind>&& binds);
    ~Query() = default;

    ...

private:
    std::string m_query;
    std::vector<Bind> m_binds;
};

Query::Query(const char* query, std::initializer_list<Bind>&& binds) : m_query(query), m_binds(binds) {}


class Bind {
    friend Query;
public:
    explicit Bind(int32_t i);
    explicit Bind(int64_t i);
    explicit Bind(uint32_t i);
    explicit Bind(float f);
    explicit Bind(const char* str);

private:
    int bind(sqlite3_stmt* stmt, int column);

    ColumnType m_type;
    union {
        int64_t m_i;
        float m_f;
        const char* m_str;
    };
    size_t m_str_size;
};

int main()
{
    Database db;
    auto result = db.run(Query(
        "INSERT INTO users VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        Bind(id),
        Bind(first_name),
        Bind(last_name),
        Bind(age),
        Bind(height),
        Bind(weight),
        Bind(siblings),
        Bind(hometown),
        Bind(mom),
        Bind(dad),
        Bind(num_pets),
        Bind(os::time_since_epoch()),
        Bind(location),
        Bind(json),
    }));
    return 0;
}

最佳答案

内部std::initializer_list<T>只是几个指针。这些没什么好搬的。所以通过 &&没有多大意义。标准库按值获取它,我建议你也这样做。 Bind里面没什么可搬的要么。

如果全部Bind构造函数只有一个参数,您可以制作一个可变参数构造函数并构造每个 Bind就地 emplace_back() :

class Query {
public:
    template<class... Bind_args>
    Query(const char* query, Bind_args&&... bind_args) {
        m_binds.reserve(sizeof...(Bind_args));
        (m_binds.emplace_back(std::forward<Bind_args>(bind_args)), ...);
    }

private:
    std::vector<Bind> m_binds;
};

这将简化 Query build

query("INSERT INTO users VALUES (?, ?, ?)", 1, "33", 2.f);

如果不进行概要分析,很难说它是否会更有效率。如今,编译器(和链接器)可以非常擅长代码优化,您描述的所有这些开销都可能被完全优化掉。

如果带有折叠表达式的 C++17 不可用,您可以将折叠表达式替换为 C++11 版本:

int sink[] = {(m_binds.emplace_back(std::forward<Bind_args>(bind_args)), 0)...};
(void)sink;

The Bind interface needs to support multiple arguments

然后这些参数可以打包成元组:

class Query {
public:
    template<class... Tuples>
    Query(const char* query, Tuples&&... bind_arg_tuples) {
        m_binds.reserve(sizeof...(Tuples));
        (emplace_from_tuple(std::forward<Tuples>(bind_arg_tuples)), ...);
    }

private:
    template<class Tuple>
    void emplace_from_tuple(Tuple&& arg_tuple) {
        emplace_from_tuple(std::forward<Tuple>(arg_tuple), 
            std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
    }

    template<class Tuple, std::size_t... is>
    void emplace_from_tuple(Tuple&& arg_tuple, std::index_sequence<is...>) {
        m_binds.emplace_back(std::get<is>(std::forward<Tuple>(arg_tuple))...);
    }

private:
    std::vector<Bind> m_binds;
};

query("INSERT INTO users VALUES (?, ?, ?)", 
    std::tuple(1, 2), std::tuple("33", "44"), std::tuple(2.f, 3.f));

此代码避免调用 Bind 的复制构造函数并正确移动所有参数(包括只能移动的类型,如 std::unique_ptr )。但对于轻量化Bind反对这可能是一个不必要的过度复杂化。

关于c++ - 我创建了一个库,想知道设计是否效率低下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58987788/

相关文章:

c++ - for_each 和转换

c++ - 基于 std::vector<string> 的内容动态设置顺序的模式

c++ - 为一些具有模板参数限制的外部模板类定义部分特化

c++ - 为什么编译器不为 size_t 的负值生成警告?

c++ - cublasSdot 的工作速度比 cublasSgemm 慢

c++ - 如何将 cpp_dec_float_50 转换为 cpp_int?关于一般的 float ?

c++ - QComboBox 项目文本可以包含 2 种颜色吗?

c++ - Clang 3.7.0 提示类不是文字,因为它不是聚合并且没有 constexpr 构造函数

c++ - 什么时候应该在 C++11 中使用 constexpr 功能?

c++ - 如何计算字符串 vector ?