pae*_*bal 17 c c++ language-construct
在与我的团队中新来的开发人员讨论之后,我意识到在C++中仍然存在使用C构造的习惯,因为它们应该更好(即更快,更精简,更漂亮,选择你的理由).
与类似的C++构造相比,有哪些示例值得共享,显示C构造?
对于每个示例,我需要阅读C++构造与原始C构造一样好或甚至更好的原因.目的是提供一些在C++代码中被认为有些危险/不安全的C构造的替代方案(C++ 0x只有在只有明确标记为C++ 0x的情况下才能接受答案).
我将在答案(结构内联初始化)下面作为示例发布.
注1:请每个案例一个答案.如果您有多个案例,请发布多个答案
注2:这不是C问题.不要在此问题中添加"C"标签. 这不应该成为C++和C之间的斗争.只研究C++的C子集的一些结构,以及它们在其他C++"工具包"中的替代方案.
注3:这不是一个抨击C的问题.我想要理由.吹嘘,抨击和未经证实的比较将被下调.提及没有C等价物的C++特性可以被认为是不可能的主题:我希望并排放置一个针对C++特性的C特征.
小智 34
在C:
Resource r;
r = Acquire(...);
... Code that uses r ...
Release(r);
Run Code Online (Sandbox Code Playgroud)
例如,Resource可以是指向内存的指针,Acquire/Release将分配/释放该内存,或者它可以是一个打开的文件描述符,其中Acquire/Release将打开/关闭该文件.
这提出了许多问题:
Releaser.如果r在同一范围内获取和发布,则代码不会自行记录.Resource r和r.Acquire(...),r实际上是访问,尽管被初始化.这是错误的来源.应用RAII(资源获取是初始化)方法,我们在C++中获得
class ResourceRAII
{
Resource rawResource;
public:
ResourceRAII(...) {rawResource = Acquire(...);}
~ResourceRAII() {Release(rawResource);}
// Functions for manipulating the resource
};
...
{
ResourceRAII r(...);
... Code that uses r ...
}
Run Code Online (Sandbox Code Playgroud)
C++版本将确保您不会忘记释放资源(如果这样做,您会发生内存泄漏,调试工具更容易检测到).它迫使程序员明确说明资源的数据流是如何流动的(即:如果它只存在于函数的范围内,这将通过堆栈上的ResourceRAII构造来表明).在创建资源对象和资源无效的销毁之间没有任何意义.
它也是例外安全!
Joh*_*McG 27
C风格:
#define max(x,y) (x) > (y) ? (x) : (y)
Run Code Online (Sandbox Code Playgroud)
C++风格
inline template<typename T>
const T& max(const T& x, const T& y)
{
return x > y ? x : y;
}
Run Code Online (Sandbox Code Playgroud)
更喜欢C++方法的理由:
Cat*_*lus 18
C-风格:
int **foo = new int*[n];
for (int x = 0; x < n; ++x) foo[x] = new int[m];
// (...)
for (int x = 0; x < n; ++x) delete[] foo[x];
delete[] foo;
Run Code Online (Sandbox Code Playgroud)
C++ - 风格:
std::vector< std::vector<int> > foo(n, std::vector<int>(m));
// (...)
Run Code Online (Sandbox Code Playgroud)
为什么STL容器更好:
Ono*_*cci 17
#define vs. const
我一直看到这样的代码来自长期编码C的开发人员:
#define MYBUFSIZE 256
. . .
char somestring[MYBUFSIZE];
Run Code Online (Sandbox Code Playgroud)
等等
在C++中,这会更好:
const int MYBUFSIZE = 256;
char somestring[MYBUFSIZE];
Run Code Online (Sandbox Code Playgroud)
当然,更好的是开发人员使用std :: string而不是char数组,但这是一个单独的问题.
C宏的问题很多 - 在这种情况下,类型检查不是主要问题.
从我所看到的情况来看,对于C程序员转换为C++而言,这似乎是一个非常难的习惯.
Ste*_*eve 14
void AddUser(LPCSTR lpcstrName, int iAge, const char *lpcstrAddress);
void AddUserByNameOnly(LPCSTR lpcstrName)
{
AddUser(lpcstrName, -1,NULL);
}
Run Code Online (Sandbox Code Playgroud)
void User::Add(LPCSTR lpcstrName, int iAge=-1, const char *lpcstrAddress=NULL);
Run Code Online (Sandbox Code Playgroud)
允许程序员用更少的源代码行以更紧凑的形式表达程序的功能.还允许将未使用参数的默认值表示为最接近实际使用位置的值.对于调用者,简化了类/结构的接口.
Kon*_*lph 13
C的qsort功能与C++的sort功能模板.后者通过模板提供类型安全,模板具有明显且不太明显的后果:
sort稍微容易一些(不需要指定元素的大小).sort将执行更快的比qsort,因为内联的比较变得微不足道.对于C版本中必需的函数指针,情况并非如此.下面的例子说明的使用qsort对sort的C风格阵列上int.
int pint_less_than(void const* pa, void const* pb) {
return *static_cast<int const*>(pa) - *static_cast<int const*>(pb);
}
struct greater_than {
bool operator ()(int a, int b) {
return a > b;
}
};
template <std::size_t Size>
void print(int (&arr)[Size]) {
std::copy(arr, arr + Size, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
int main() {
std::size_t const size = 5;
int values[] = { 4, 3, 6, 8, 2 };
{ // qsort
int arr[size];
std::copy(values, values + size, arr);
std::qsort(arr, size, sizeof(int), &pint_less_than);
print(arr);
}
{ // sort
int arr[size];
std::copy(values, values + size, arr);
std::sort(arr, arr + size);
print(arr);
}
{ // sort with custom comparer
int arr[size];
std::copy(values, values + size, arr);
std::sort(arr, arr + size, greater_than());
print(arr);
}
}
Run Code Online (Sandbox Code Playgroud)
有时,我们需要在C++中简单地聚合数据.数据有些独立,通过封装来保护它不值得付出努力.
// C-like code in C++
struct CRect
{
int x ;
int y ;
} ;
void doSomething()
{
CRect r0 ; // uninitialized
CRect r1 = { 25, 40 } ; // vulnerable to some silent struct reordering,
// or adding a parameter
}
Run Code Online (Sandbox Code Playgroud)
; 我看到上面的代码有三个问题:
下面的代码将内联构造函数(如果真的很有用),因此将具有零成本(如上面的C代码):
// C++
struct CRect
{
CRect() : x(0), y(0) {} ;
CRect(int X, int Y) : x(X), y(Y) {} ;
int x ;
int y ;
} ;
void doSomething()
{
CRect r0 ;
CRect r1(25, 40) ;
}
Run Code Online (Sandbox Code Playgroud)
(奖金是我们可以添加一个运算符==方法,但这个奖金超出了主题,所以值得一提,但不值得作为答案.)
亚当罗森菲尔德做了一个有趣的评论,我觉得很有意思:
C99允许命名的初始值设定项: CRect r = {.x = 25,.y = 40}
这不会在C++中编译.我想这应该添加到C++中,如果仅用于C兼容性.无论如何,在C中,它缓解了这个答案中提到的问题.
在C:
#include <stdio.h>
int main()
{
int num = 42;
printf("%s%d%c", "Hello World\n", num, '\n');
return 0;
}
Run Code Online (Sandbox Code Playgroud)
格式字符串在运行时解析,这意味着它不是类型安全的.
在C++中:
#include <iostream>
int main()
{
int num = 42;
std::cout << "Hello World\n" << num << '\n';
}
Run Code Online (Sandbox Code Playgroud)
数据类型在编译时是已知的,因为不需要格式字符串,所以也可以输入更少的数据类型.
继fizzer在C++构建的帖子取代C构造之后,我将在这里写下我的答案:
警告:下面提出的C++解决方案不是标准的C++,而是g ++和Visual C++的扩展,并且被提议作为C++ 0x的标准(感谢Fizzer对此的评论)
请注意,Johannes Schaub - litb的答案提供了另一种符合C++ 03标准的方法.
如何提取C数组的大小?
来源:C++宏什么时候有用?
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
Run Code Online (Sandbox Code Playgroud)
与当前线程中讨论的"首选"模板解决方案不同,您可以将其用作常量表达式:
char src[23];
int dest[ARRAY_SIZE(src)];
Run Code Online (Sandbox Code Playgroud)
我不同意Fizzer,因为有一个模板化的解决方案能够生成一个常量表达式(事实上,模板的一个非常有趣的部分是它们在编译时生成常量表达式的能力)
无论如何,ARRAY_SIZE是一个能够提取C数组大小的宏.我不会详细说明C++中的宏:目的是找到一个相同或更好的C++解决方案.
以下C++版本没有任何宏问题,并且可以以相同的方式执行任何操作:
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
Run Code Online (Sandbox Code Playgroud)
如以下代码所示:
#include <iostream>
// C-like macro
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
// C++ replacement
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
int main(int argc, char **argv)
{
char src[23];
char * src2 = new char[23] ;
int dest[ARRAY_SIZE(src)];
int dest2[array_size(src)];
std::cout << "ARRAY_SIZE(src) : " << ARRAY_SIZE(src) << std::endl ;
std::cout << "array_size(src) : " << array_size(src) << std::endl ;
std::cout << "ARRAY_SIZE(src2) : " << ARRAY_SIZE(src2) << std::endl ;
// The next line won't compile
//std::cout << "array_size(src2) : " << array_size(src2) << std::endl ;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这将输出:
ARRAY_SIZE(src) : 23
array_size(src) : 23
ARRAY_SIZE(src2) : 4
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,宏错误地指向了一个数组的指针,因此返回了一个错误的值(4,而不是23).相反,模板拒绝编译:
/main.cpp|539|error: no matching function for call to ‘array_size(char*&)’|
Run Code Online (Sandbox Code Playgroud)
从而证明模板解决方案是:*能够在编译时生成常量表达式*如果以错误的方式使用,则能够停止编译
因此,总而言之,模板的参数是:
注意:感谢Microsoft实现strcpy_s for C++ ...我知道有一天我会为我服务... ^ _ ^
http://msdn.microsoft.com/en-us/library/td1esda9.aspx
Fizzer确实正确评论这在当前的C++标准中是无效的,并且非常正确(因为我可以在g ++上验证-pedantic选项已经检查).
尽管如此,今天不仅可以在两个主要的编译器(即Visual C++和g ++)上使用它,但这被考虑用于C++ 0x,如以下草案中所提出的:
C++ 0x的唯一变化可能是:
inline template <typename T, size_t size>
constexpr size_t array_size(T (&p)[size])
{
//return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
Run Code Online (Sandbox Code Playgroud)
(注意constexpr关键字)
Johannes Schaub - litb的回答提供了另一种符合C++ 03标准的方法.我将复制粘贴源文件以供参考,但请访问他的答案以获得完整的示例(并upmod它!):
template<typename T, size_t N> char (& array_size(T(&)[N]) )[N];
Run Code Online (Sandbox Code Playgroud)
用作:
int p[] = { 1, 2, 3, 4, 5, 6 };
int u[sizeof array_size(p)]; // we get the size (6) at compile time.
Run Code Online (Sandbox Code Playgroud)
我脑中的许多神经元都被炒得让我理解了array_size它的本质(提示:它是一个返回对N个字符数组的引用的函数).
:-)
| 归档时间: |
|
| 查看次数: |
3177 次 |
| 最近记录: |