- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一段通用代码,其性能对我来说很重要,因为我面临着与用 C
编写的著名手工代码的运行时间相匹配的挑战。在开始使用 noexcept
之前,我的代码运行时间为 4.8 秒。通过将 noexcept
放在我能想到的每个地方(我知道这不是一个好主意,但我这样做是为了学习),代码加速了 3.3 秒。然后我开始恢复更改,直到获得更好的性能(3.1 秒)并保持单个 noexcept
!
问题是:为什么这个特殊的 noexcept
有这么大的帮助?在这里:
static const AllActions& allActions_() noexcept {
static const AllActions instance = computeAllActions();
return instance;
}
有趣的是,我还有另一个类似的功能,没有 noexcept
也很好(即放置 noexcept
不会提高性能):
static const AllMDDeltas& mdDeltas_() {
static const AllMDDeltas instance = computeAllMDDeltas();
return instance;
}
我的代码(执行递归深度优先搜索)多次调用这两个函数,因此第二个函数对于整体性能与第一个函数一样重要。
P.S. 下面是更多上下文的相关代码(引用的函数和它们调用的函数在 list 的末尾):
/// The sliding-tile puzzle domain.
/// \tparam nRows Number of rows on the board.
/// \tparam nRows Number of columns on the board.
template <int nRows, int nColumns>
struct SlidingTile : core::sb::DomainBase {
/// The type representing the cost of actions in the domain. Every
/// domain must provide this name.
using CostType = int;
using SNeighbor =
core::sb::StateNeighbor<SlidingTile>; ///< State neighbor type.
using ANeighbor =
core::sb::ActionNeighbor<SlidingTile>; ///< Action neighbor type.
/// The type for representing an action. The position of the tile being moved.
using Action = int;
/// Number of positions.
static constexpr int size_ = nRows * nColumns;
/// The type for the vector of actions for a given position of the blank.
using BlankActions = std::vector<ANeighbor>;
/// The type for all the actions in the domain.
using AllActions = std::array<BlankActions, size_>;
/// The type for two-dimension array of Manhattan distance heuristic deltas
/// for a given tile. The indexes are from and to of an action.
using TileMDDeltas = std::array<std::array<int, size_>, size_>;
/// The type for all Manhattan distance heuristic deltas.
using AllMDDeltas = std::array<TileMDDeltas, size_>;
/// The type for raw state representation.
using Board = std::array<int, size_>;
/// Initializes the ordered state.
SlidingTile() {
int i = -1;
for (auto &el : tiles_) el = ++i;
}
/// Initializes the state from a string, e.g. "[1, 4, 2, 3, 0, 5]" or "1 4 2
/// 4 0 5" for 3x2 board.
/// \param s The string.
SlidingTile(const std::string &s) {
int i = -1;
for (auto el : core::util::split(s, {' ', ',', '[', ']'})) {
tiles_[++i] = std::stoi(el);
if (tiles_[i] == 0) blank_ = i;
}
}
/// The default copy constructor.
SlidingTile(const SlidingTile &) = default;
/// The default assignment operator.
/// \return Reference to the assigned state.
SlidingTile &operator=(const SlidingTile &) = default;
/// Returns the array of tiles at each position.
/// \return The raw representation of the state, which is the array of tiles
/// at each position..
const Board &getTiles() const { return tiles_; }
/// Applies an action to the state.
/// \param a The action to be applied, i.e. the next position of the blank
/// on the board.
/// \return The state after the action.
SlidingTile &apply(Action a) {
tiles_[blank_] = tiles_[a];
blank_ = a;
return *this;
}
/// Returns the reverse of the given action in this state.
/// \param a The action whose reverse is to be returned.
/// \return The reverse of the given action.
Action reverseAction(Action a) const {
(void)a;
return blank_;
}
/// Computes the state neighbors of the state.
/// \return Vector of state neighbors of the state.
std::vector<SNeighbor> stateSuccessors() const {
std::vector<SNeighbor> res;
for (auto a : actionSuccessors()) {
auto n = SlidingTile{*this}.apply(a.action());
res.push_back(std::move(n));
}
return res;
}
/// Computes the action neighbors of the state.
/// \return Vector of action neighbors of the state.
const std::vector<ANeighbor> &actionSuccessors() const {
return allActions_()[blank_];
}
/// The change in the Manhattan distance heuristic to the goal state with
/// ordered tiles and the blank at position 0 due to applying the given action.
/// \param a The given action.
/// \return The change in the Manhattan distance heuristic to the goal state
/// with ordered pancake due to applying the given action.
int mdDelta(Action a) const {
return mdDeltas_()[tiles_[a]][a][blank_];
}
/// Computes the Manhattan distance heuristic to the goal state with
/// ordered tiles and the blank at position 0.
/// \return The Manhattan distance heuristic to the goal state with
/// ordered tiles and the blank at position 0.
int mdHeuristic() const {
int res = 0;
for (int pos = 0; pos < size_; ++pos)
if (pos != blank_)
res += rowDist(pos, tiles_[pos]) + colDist(pos, tiles_[pos]);
return res;
}
/// Computes the hash-code of the state.
/// \return The hash-code of the state.
std::size_t hash() const {
boost::hash<Board> v_hash;
return v_hash(tiles_);
}
/// Dumps the state to the given stream.
/// \tparam The stream type.
/// \param o The stream.
/// \return The modified stream.
template <class Stream> Stream &dump(Stream &o) const {
return o << tiles_;
}
/// Randomly shuffles the tiles.
void shuffle() {
auto old = tiles_;
while (old == tiles_)
std::random_shuffle(tiles_.begin(), tiles_.end());
}
/// The equality operator.
/// \param rhs The right-hand side of the operator.
/// \return \c true if the two states compare equal and \c false
/// otherwise.
bool operator==(const SlidingTile &rhs) const {
if (blank_ != rhs.blank_) return false;
for (int i = 0; i < size_; ++i)
if (i != blank_ && tiles_[i] != rhs.tiles_[i]) return false;
return true;
}
/// Returns a random state.
/// \return A random state.
static SlidingTile random() {
SlidingTile res{};
res.shuffle();
return res;
}
private:
/// Tile at each position. This does not include the position of the blank,
/// which is stored separately.
std::array<int, size_> tiles_;
/// Blank position.
int blank_{};
/// Computes the row number corresponding to the given position.
/// \return The row number corresponding to the given position.
static int row(int pos) { return pos / nColumns; }
/// The difference between the row numbers corresponding to the two given
/// positions.
/// \return The difference between the row numbers corresponding to the two
/// given positions.
static int rowDiff(int pos1, int pos2) { return row(pos1) - row(pos2); }
/// The distance between the row numbers corresponding to the two given
/// positions.
/// \return The distance between the row numbers corresponding to the two
/// given positions.
static int rowDist(int pos1, int pos2) {
return std::abs(rowDiff(pos1, pos2));
}
/// Computes the column number corresponding to the given position.
/// \return The column number corresponding to the given position.
static int col(int pos) { return pos % nColumns; }
/// The difference between the column numbers corresponding to the two given
/// positions.
/// \return The difference between the column numbers corresponding to the
/// two given positions.
static int colDiff(int pos1, int pos2) { return col(pos1) - col(pos2); }
/// The distance between the column numbers corresponding to the two given
/// positions.
/// \return The distance between the column numbers corresponding to the
/// two given positions.
static int colDist(int pos1, int pos2) {
return std::abs(colDiff(pos1, pos2));
}
/// Computes the actions available for each position of the blank.
static AllActions computeAllActions() {
AllActions res;
for (int blank = 0; blank < size_; ++blank) {
// the order is compatible with the code of Richard Korf.
if (blank > nColumns - 1)
res[blank].push_back(Action{blank - nColumns});
if (blank % nColumns > 0)
res[blank].push_back(Action{blank - 1});
if (blank % nColumns < nColumns - 1)
res[blank].push_back(Action{blank + 1});
if (blank < size_ - nColumns)
res[blank].push_back(Action{blank + nColumns});
}
return res;
}
/// Computes the heuristic updates for all the possible moves.
/// \return The heuristic updates for all the possible moves.
static AllMDDeltas computeAllMDDeltas() {
AllMDDeltas res;
for (int tile = 1; tile < size_; ++tile) {
for (int blank = 0; blank < size_; ++blank) {
for (const ANeighbor &a: allActions_()[blank]) {
int from = a.action(), to = blank;
res[tile][from][to] =
(rowDist(tile, to) - rowDist(tile, from)) +
(colDist(tile, to) - colDist(tile, from));
}
}
}
return res;
}
/// Returns all the actions.
/// \note See http://stackoverflow.com/a/42208278/2725810
static const AllActions& allActions_() noexcept {
static const AllActions instance = computeAllActions();
return instance;
}
/// Returns all the updates of the MD heuristic.
static const AllMDDeltas& mdDeltas_() {
static const AllMDDeltas instance = computeAllMDDeltas();
return instance;
}
};
最佳答案
与 computeAllMDDeltas
不同,函数 computeAllActions
包含对 push_back
的一些调用,这可能会执行一些内存分配。如果底层分配器出现异常,例如内存不足,这可能会抛出。这是编译器无法优化的东西,因为它取决于运行时参数。
添加noexcept
告诉编译器不能出现这些错误,这样他就可以省略异常处理的代码。
关于c++ - 为什么这个 noexcept 对性能如此重要,而类似的其他 noexcept 却没有?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42809905/
考虑: class test { private: int n; int impl () const noexcept { return
#include class A { std::vector vec; void swap( A & other) noexcept(noexcept(vec.swap(other.
在 the C++ standard有如下定义: template void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a,
从 c++20 开始,我们可以使用 consteval 说明符定义立即数函数。当一个函数被声明为 consteval 时,对该函数的每次调用都必须产生一个编译时常量,否则该程序就是病式的。此外,由于
为什么 noexcept 运算符采用表达式而不是函数签名/声明? 考虑以下虚拟示例: #include void strProcessor(const std::string& str) noexc
我有一段通用代码,其性能对我来说很重要,因为我面临着与用 C 编写的著名手工代码的运行时间相匹配的挑战。在开始使用 noexcept 之前,我的代码运行时间为 4.8 秒。通过将 noexcept 放
如果我将函数标记为 noexcept(false),或任何其他计算结果为 false 的表达式,这意味着什么? (1) 我是否向编译器保证该函数可以抛出异常?,(2) 还是我不保证它是否可以抛出异常?
我们遇到过这种情况,想知道解决它的最佳方法 template struct A : T { A(T &&t) noexcept(noexcept(T(std::move(t)))) :T
此代码使用 gcc 4.8.2 (-std=c++11) 编译失败,但使用 clang 3.4 (trunk) (-std=c++11) 编译: #include #include struct
当函数标记为 noexcept 时,GCC 或 Clang 中是否有一个标志会抛出编译时错误(或警告)尝试调用未标记为 noexcept 的函数? 如果不是,那么当您删除 noexcept 时,您应该
假设我有一个类 class C : public B { public: C() noexcept; } noexcept 说明符是否需要基类的相同 promise ?也就是说,当我考虑使
长标题:为什么 std:variant 的 operator=(T&& t) 的 noexcept 规范不依赖于内部类型的析构函数的 noexcept 规范? 我可以在 cppreference 上看
在下面的代码中,我尝试对函数使用条件异常规范,但编译失败,尽管如果在函数外部使用它就可以了。 void may_throw(); // ERROR: expression must have bool
目前在C++这些都不可能,编译器提示它需要一个表达式。 这对我来说似乎微不足道,如果您正在构建一个具有可变数量类型的类似元组的对象,如何检查所有这些类型是否都是 nothrow default/mov
在 The C++ Programming Language 一书中写道,您可以将函数声明为有条件的 noexcept .例如: template void my_fct(T& x) noexcept
根据this question的回答,默认移动构造函数可以定义为 noexcept在一定条件下。例如,下面的类生成一个 noexcept移动构造函数: class C {}; 根据对this ques
拿这个代码: template void my_func() { T::some_method(); } int main() { std::cout ()) ? "noexcept" :
这个声明没问题: void memberFunction(T& functor, double value)noexcept(noexcept(functor(value))); 对于一个 templ
我在思考 noexcept 时遇到了一些麻烦。 template int pop(int idx) noexcept(noexcept(SIZE > 0)) // this is what I do
为什么 std::decay 不从函数指针中移除 noexcept 说明符? 例如这符合 c++17 #include template struct is_noexcept {}; templat
我是一名优秀的程序员,十分优秀!