如果

时间:2016-10-22 21:11:32

标签: c++ performance

鉴于以下内容:

class ReadWrite {
public:
    int Read(size_t address);
    void Write(size_t address, int val);
private:
    std::map<size_t, int> db;
}

在读取函数中,当访问一个先前没有写过的地址时,我想抛出异常指定这样的错误或者允许并返回0,换句话说我想使用std::map<size_t, int>::operator[]()或{{ 1}},取决于用户可以设置的一些bool值。所以我添加以下内容:

std::map<size_t, int>::at()

问题是: 通常,程序将在程序开始时调用allow或none,然后进行多次访问。因此,性能方面,这段代码很糟糕,因为它每次执行检查class ReadWrite { public: int Read(size_t add) { if (allow) return db[add]; return db.at(add);} void Write(size_t add, int val) { db[add] = val; } void Allow() { allow = true; } private: bool allow = false; std::map<size_t, int> db; } ,通常它总是为真或总是为假。 那你怎么解决这个问题呢?

修改

虽然这个类的描述用例(一个或没有if (allow))很可能是不确定的,所以我必须允许用户动态调用Allow()

另一个编辑:

使用函数指针的解决方案:使用无法由编译器内联的函数指针会导致性能开销怎么办?如果我们使用Allow()而不是解决问题?

4 个答案:

答案 0 :(得分:1)

  

通常情况下,程序会有一次允许或者一次调用   程序的开始,然后很多访问。所以,   性能方面,这段代码很糟糕,因为它每次都会执行   检查是否(允许)通常它总是正确或总是   假。那你怎么解决这个问题呢?

我不会,CPU会 Branch Prediction会发现答案很可能在很长一段时间内都是相同的,所以它能够非常优化硬件级别的分支。它仍然会产生一些开销,但是可以忽略不计。

如果您确实需要优化您的计划,我认为您最好使用std::unordered_map代替std::map,或者转移到更快的地图实施,例如google::dense_hash_map。与地图查找相比,该分支无关紧要。

答案 1 :(得分:0)

如果您想减少时间成本,则必须增加内存成本。接受这一点,您可以使用函数指针执行此操作。以下是我的回答:

class ReadWrite {
public:
   void Write(size_t add, int val) { db[add] = val; }
   // when allowed, make the function pointer point to read2
   void Allow() { Read = &ReadWrite::read2;}
   //function pointer that points to read1 by default
   int (ReadWrite::*Read)(size_t) = &ReadWrite::read1;
private: 
   int read1(size_t add){return db.at(add);}
   int read2(size_t add) {return db[add];}
   std::map<size_t, int> db;
};

可以将函数指针作为其他成员函数调用。举个例子:

ReadWrite rwObject;
//some code here
//...
rwObject.Read(5); //use of function pointer
//

请注意,c ++ 11可以使用非静态数据成员初始化,因此int (ReadWrite::*Read)(size_t) = &ReadWrite::read1;可能无法使用旧版本进行编译。在这种情况下,您必须显式声明一个构造函数,其中可以完成函数指针的初始化。

答案 2 :(得分:0)

您可以使用指针进行操作。

class ReadWrite {
public:
    void Write(size_t add, int val) { db[add] = val; }
    int Read(size_t add) { (this->*Rfunc)(add); }
    void Allow() { Rfunc = &ReadWrite::Read2; }
private:
    std::map<size_t, int> db;
    int Read1(size_t add) { return db.at(add); }
    int Read2(size_t add) { return db[add]; }
    int (ReadWrite::*Rfunc)(size_t) = &ReadWrite::Read1;
}

答案 3 :(得分:0)

如果您想要运行时动态行为,您必须在运行时(在您希望逻辑动态运行的那一点)为它付费。

根据运行时条件,您需要在调用Read的位置执行不同的行为,并且您必须检查该条件。 无论你的overhad是函数指针调用还是分支,你都会发现跳转或调用程序中的不同位置,具体取决于客户端调用allowRead代码。

注意:描述和修复真正的瓶颈 - 不是可疑的瓶颈。 (如果您通过确认您的怀疑或找出您对性能的假设错误的原因,您将了解更多信息。