Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C+进行重构+;11 给出了C++程序员提供的新工具集,旨在简化代码,表达能力,效率,浏览他们的旧代码,并调整(一些毫无意义,一些成功)实现他们的目标。虽然尽量不要在这些工作上浪费太多时间,只是进行非侵入性和自我包含的更改,但最佳做法是什么_C++_C++11_Refactoring - Fatal编程技术网

用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);