用C+进行重构+;11 给出了C++程序员提供的新工具集,旨在简化代码,表达能力,效率,浏览他们的旧代码,并调整(一些毫无意义,一些成功)实现他们的目标。虽然尽量不要在这些工作上浪费太多时间,只是进行非侵入性和自我包含的更改,但最佳做法是什么
让我划掉显而易见的:用C+进行重构+;11 给出了C++程序员提供的新工具集,旨在简化代码,表达能力,效率,浏览他们的旧代码,并调整(一些毫无意义,一些成功)实现他们的目标。虽然尽量不要在这些工作上浪费太多时间,只是进行非侵入性和自我包含的更改,但最佳做法是什么,c++,c++11,refactoring,C++,C++11,Refactoring,让我划掉显而易见的: 使用auto运行基于迭代器的循环: for (std::vector<foo>::const_iterator it(lala.begin()), ite(lala.end()); it != ite; ++it); // becomes for (auto it(lala.cbegin()), ite(lala.cend()); it != ite; ++it); 要使类不可继承,只需将其声明为“final”,并删除实现这种行为的代码 使用de
- 使用auto运行基于迭代器的循环:
for (std::vector<foo>::const_iterator it(lala.begin()), ite(lala.end()); it != ite; ++it); // becomes for (auto it(lala.cbegin()), ite(lala.cend()); it != ite; ++it);
- 要使类不可继承,只需将其声明为“final”,并删除实现这种行为的代码
- 使用delete关键字显式隐藏构造函数/析构函数,而不是将它们声明为私有(例如创建基于堆的对象、不可复制对象等的代码)
- 将仅为简化单个STL算法的执行而创建的普通函子转换为lambda函数(除了减少代码混乱外,还保证了内联调用)
- 仅使用智能指针简化对象的RAII包装
- 去掉bind1st、bind2nd,只需使用bind
- 用
提供的标准代码替换类型特征的手写代码(是\u ptr\u但\u not \u call \u表示常量\u ptr等:) - 停止为STL中现在实现的功能包括boost头(boost\u STATIC\u ASSERT vs STATIC\u ASSERT)
- 为类提供移动语义(尽管这不符合脏/快/易更改的条件)
- 在可能的情况下使用nullptr代替NULL宏,并删除将0转换为对象类型填充指针容器的代码
std::vector<foo*> f(23); for (std::size_t i(0); i < 23; ++i) { f[i] = static_cast<foo*>(0); } // becomes std::vector<foo*> f(23, nullptr);
- 替换将临时对象放入容器中的代码,并希望优化器在可用时使用“emplace”函数省略副本,以便完美地转发参数并直接将对象构造到容器中,而无需临时
vecOfPoints.push_back(Point(x,y,z)); // so '03 vecOfPoints.emplace_back(x, y, z); // no copy or move operations performed
std::vector<int> container;
for (auto const & i : container)
std::cout << i << std::endl;
std::向量容器;
用于(自动const&i:容器)
std::cout1。取代兰德
C++11最大的好处之一是用中的所有可用选项取代了rand()
。在许多情况下,替换rand()
应该是直截了当的
斯蒂芬·拉瓦维(Stephan T.Lavavej)的演讲可能最有力地表达了这一点。示例显示了使用rand()
从[0,10]
得到的均匀整数分布:
三,。使用constexpr代替模板元编程
如果您处理的是文本,那么在某些情况下,在模板元编程中使用constexpr函数可能会生成更清晰的代码,并且可能编译得更快。本文提供了一个使用模板元编程确定素数的示例:
struct false_type
{
typedef false_type type;
enum { value = 0 };
};
struct true_type
{
typedef true_type type;
enum { value = 1 };
};
template<bool condition, class T, class U>
struct if_
{
typedef U type;
};
template <class T, class U>
struct if_<true, T, U>
{
typedef T type;
};
template<size_t N, size_t c>
struct is_prime_impl
{
typedef typename if_<(c*c > N),
true_type,
typename if_<(N % c == 0),
false_type,
is_prime_impl<N, c+1> >::type >::type type;
enum { value = type::value };
};
template<size_t N>
struct is_prime
{
enum { value = is_prime_impl<N, 2>::type::value };
};
template <>
struct is_prime<0>
{
enum { value = 0 };
};
template <>
struct is_prime<1>
{
enum { value = 0 };
};
并说:
hash_算法和s都有一个默认值,这一事实在混乱的代码中丢失了,在维护过程中很容易成为问题。相反,我们可以考虑数据成员的初始化:
请注意,在C++11中,使用类内成员初始值设定项的类是无效的,尽管在C++14中已删除此限制
五,。使用cstdint中的固定宽度整数类型,而不是手动滚动的typedefs
由于C++11标准使用C99作为标准参考,因此我们也得到了C99。例如:
int8_t
int16_t
int32_t
int64_t
intptr_t
尽管其中有几个是可选的,但对于精确的宽度整数类型,C99节7.18.1.1
中的以下内容适用:
这些类型是可选的。但是,如果实现提供宽度为8的整数类型,
16、32或64位,无填充位,和(对于有符号类型)
如果有2的补码表示,则应定义
对应的typedef名称
功能:std::move
“表示复制和移动资源之间的明显区别”
std::字符串tmp(“移动”);
std::向量v;
v、 推回(标准::移动(tmp));
//此时,tmp仍然是有效对象,但处于未指定的状态
//它的资源已被移动,现在存储在vector容器中。
使用
为了
为了避免类似这样的问题(Herb Sutter的链接文章解释了新方法优越性的其他原因)这篇博客文章建议,如果一个类中的所有所有权都遵循RAII原则,就可以摆脱C++11中的三/四/五规则
然而,Scott Meyers表明,如果稍微更改代码(例如,为了调试),不显式编写析构函数、复制/移动构造函数和赋值运算符可能会导致一些微妙的问题。然后,他建议显式声明默认值(C++11特性)这些函数:
~MyClass() = default;
MyClass( const MyClass& ) = default;
MyClass( MyClass&& ) = default;
MyClass& operator=( const MyClass& ) = default;
MyClass& operator=( MyClass&& ) = default;
我会将委托构造函数和类内成员初始值设定项添加到列表中
通过使用委托构造函数和类内初始化简化
使用C++03:
class A
{
public:
// The default constructor as well as the copy constructor need to
// initialize some of the members almost the same and call init() to
// finish construction.
A(double data) : id_(0), name_(), data_(data) {init();}
A(A const& copy) : id_(0), name_(), data_(copy.data_) {init();}
void init()
{
id_ = getNextID();
name_ = getDefaultName();
}
int id_;
string name_;
double data_;
};
使用C++11:
class A
{
public:
// With delegating constructor, the copy constructor can
// reuse this constructor and avoid repetitive code.
// In-line initialization takes care of initializing the members.
A(double data) : data_(data) {}
A(A const& copy) : A(copy.data_) {}
int id_ = getNextID();
string name_ = getDefaultName();
double data_;
};
使用constexpr优化简单的数学函数,特别是在内部循环中调用时。这将允许编译器在编译时计算它们,从而节省您的时间
范例
constexpr int fibonacci(int i) {
return i==0 ? 0 : (i==1 ? 1 : fibonacci(i-1) + fibonacci(i-2));
}
另一个例子是使用std::enable_if
来限制特定模板函数/类中允许的模板参数类型。这将使您的代码更安全(如果您没有使用SFINAE来约束旧代码中可能的模板参数),因为您隐式地假定了一些关于模板类型的属性,而这只是一行额外的代码
例
struct false_type
{
typedef false_type type;
enum { value = 0 };
};
struct true_type
{
typedef true_type type;
enum { value = 1 };
};
template<bool condition, class T, class U>
struct if_
{
typedef U type;
};
template <class T, class U>
struct if_<true, T, U>
{
typedef T type;
};
template<size_t N, size_t c>
struct is_prime_impl
{
typedef typename if_<(c*c > N),
true_type,
typename if_<(N % c == 0),
false_type,
is_prime_impl<N, c+1> >::type >::type type;
enum { value = type::value };
};
template<size_t N>
struct is_prime
{
enum { value = is_prime_impl<N, 2>::type::value };
};
template <>
struct is_prime<0>
{
enum { value = 0 };
};
template <>
struct is_prime<1>
{
enum { value = 0 };
};
constexpr bool is_prime_recursive(size_t number, size_t c)
{
return (c*c > number) ? true :
(number % c == 0) ? false :
is_prime_recursive(number, c+1);
}
constexpr bool is_prime_func(size_t number)
{
return (number <= 1) ? false : is_prime_recursive(number, 2);
}
class A {
public:
A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
int a, b;
private:
HashingFunction hash_algorithm; // Cryptographic hash to be applied to all A instances
std::string s; // String indicating state in object lifecycle
};
class A {
public:
A(): a(7), b(5) {}
A(int a_val) : a(a_val), b(5) {}
A(D d) : a(7), b(g(d)) {}
int a, b;
private:
HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A instances
std::string s{"Constructor run"}; // String indicating state in object lifecycle
};
int8_t
int16_t
int32_t
int64_t
intptr_t
std::string tmp("move");
std::vector<std::string> v;
v.push_back(std::move(tmp));
//At this point tmp still be the valid object but in unspecified state as
// its resources has been moved and now stored in vector container.
widget w(x); // old
widget w{x}; // new
~MyClass() = default;
MyClass( const MyClass& ) = default;
MyClass( MyClass&& ) = default;
MyClass& operator=( const MyClass& ) = default;
MyClass& operator=( MyClass&& ) = default;
class A
{
public:
// The default constructor as well as the copy constructor need to
// initialize some of the members almost the same and call init() to
// finish construction.
A(double data) : id_(0), name_(), data_(data) {init();}
A(A const& copy) : id_(0), name_(), data_(copy.data_) {init();}
void init()
{
id_ = getNextID();
name_ = getDefaultName();
}
int id_;
string name_;
double data_;
};
class A
{
public:
// With delegating constructor, the copy constructor can
// reuse this constructor and avoid repetitive code.
// In-line initialization takes care of initializing the members.
A(double data) : data_(data) {}
A(A const& copy) : A(copy.data_) {}
int id_ = getNextID();
string name_ = getDefaultName();
double data_;
};
constexpr int fibonacci(int i) {
return i==0 ? 0 : (i==1 ? 1 : fibonacci(i-1) + fibonacci(i-2));
}
template
<
typename T,
std::enable_if< std::is_abstract<T>::value == false, bool>::type = false // extra line
>
void f(T t)
{
// do something that depends on the fact that std::is_abstract<T>::value == false
}
enum Color{ blue, green, yellow };
bool blue = false; // error: 'blue' redefinition
enum class Color{ blue, green, yellow };
bool blue = false; // fine, no other `blue` in scope
Color cc = blue; // error! no enumerator `blue` in this scope
Color cc = Color::blue; // fine
auto c = Color::blue; // fine
enum Color{ blue, green, yellow };
std::vector<std::size_t> getVector(std::size_t x);
Color c = blue;
if (c < 10.1) { // compare Color with double !!
auto vec = getVector(c); // could be fine !!
}
enum class Color{ blue, green, yellow };
std::vector<std::size_t> getVector(std::size_t x);
Color c = Color::blue;
if (c < 10.1) { // error !
auto vec = getVector(c); // error !!
}
if (static_cast<double>(c) < 10.1) {
auto vec = getVector(static_cast<std::size_t>(c));
}
enum Color; // error!!
enum class Color; // fine
int doAsyncWork();
std::thread t(doAsyncWork);
auto fut = std::async(doAsyncWork);