474

你走多远const?您只是const在必要时制作函数,还是全力以赴并在任何地方使用它?例如,想象一个简单的 mutator,它接受一个布尔参数:

void SetValue(const bool b) { my_val_ = b; }

const真的有用吗?我个人选择广泛使用它,包括参数,但在这种情况下,我想知道它是否值得?

我还惊讶地发现,您可以const在函数声明中省略参数,但可以将其包含在函数定义中,例如:

.h 文件

void func(int n, long l);

.cpp 文件

void func(const int n, const long l)

是否有一个原因?这对我来说似乎有点不寻常。

4

31 回答 31

478

const当参数按值传递时是没有意义的,因为您不会修改调用者的对象。

错误的。

这是关于自我记录你的代码和你的假设。

如果您的代码有很多人在处理它并且您的功能不平凡,那么您应该标记const所有可以标记的内容。在编写工业级代码时,您应该始终假设您的同事是精神病患者,他们试图以任何方式得到您(尤其是因为将来通常是您自己)。

此外,正如前面有人提到的,它可能会帮助编译器优化一些东西(尽管它是一个很长的镜头)。

于 2008-09-22T20:51:03.760 回答
223

原因是const该参数仅在函数内本地应用,因为它正在处理数据的副本。这意味着函数签名无论如何都是一样的。不过,经常这样做可能是不好的风格。

我个人倾向于不使用const除了引用和指针参数。对于复制的对象,这并不重要,尽管它可以更安全,因为它在函数内发出意图信号。这真的是一个判断电话。尽管在循环某些东西时我确实倾向于使用,const_iterator但我不打算修改它,所以我猜每个人都是他自己的,只要const严格维护引用类型的正确性。

于 2008-09-22T20:15:12.630 回答
171

有时(太频繁了!)我必须解开别人的 C++ 代码。而且我们都知道,根据定义,其他人的C++ 代码几乎是一团糟 :) 所以我破译本地数据流的第一件事就是将const放入每个变量定义中,直到编译器开始咆哮。这也意味着 const 限定值参数,因为它们只是由调用者初始化的花哨的局部变量。

啊,我希望变量默认为const而非 const 变量需要可变:)

于 2008-09-22T22:00:23.173 回答
91

以下两行在功能上是等效的:

int foo (int a);
int foo (const int a);

显然,如果它是第二种方式定义的,您将无法a在主体中进行修改foo,但与外部没有区别。

真正派上const用场的是引用或指针参数:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

这说明 foo 可以采用一个大参数,也许是一个千兆字节大小的数据结构,而无需复制它。此外,它对调用者说:“Foo 不会* 更改该参数的内容。” 传递 const 引用还允许编译器做出某些性能决策。

*:除非它抛弃了 const-ness,但那是另一篇文章。

于 2008-09-22T20:36:58.863 回答
84

从 API 的角度来看,多余的 const 是不好的:

在代码中为按值传递的内在类型参数添加多余的 const会使您的 API 混乱,同时对调用者或 API 用户没有任何有意义的承诺(它只会妨碍实现)。

API 中不需要的太多“const”就像“来了”,最终人们会开始忽略“const”,因为它无处不在,而且大多数时候没有任何意义。

API 中额外 const 的“reductio ad absurdum”参数对于前两点是好的,如果更多的 const 参数是好的,那么每个可以有 const 的参数都应该有 const。事实上,如果它真的那么好,你会希望 const 成为参数的默认值,并且只有在你想更改参数时才有像“mutable”这样的关键字。

因此,让我们尽可能地尝试放入 const :

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

考虑上面的代码行。不仅声明更混乱、更长、更难阅读,而且 API 用户可以安全地忽略四个“const”关键字中的三个。然而,'const' 的额外使用使得第二行可能很危险!

为什么?

对第一个参数的快速误读char * const buffer可能会让您认为它不会修改传入的数据缓冲区中的内存——然而,事实并非如此!当快速扫描或误读时,多余的 'const' 可能会导致对 API 的危险和错误假设。


从代码实现的角度来看,多余的 const 也是不好的:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

如果 FLEXIBLE_IMPLEMENTATION 不为真,那么 API “承诺”不会以下面的第一种方式实现该功能。

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

这是一个非常愚蠢的承诺。为什么你要做出一个对你的调用者没有任何好处并且只会限制你的实现的承诺?

尽管这两者都是相同功能的完全有效的实现,但您所做的只是将一只手不必要地绑在背后。

此外,这是一个很容易(并且在法律上被规避)的非常肤浅的承诺。

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

看,尽管我承诺不这样做,但我还是以这种方式实现了它——只是使用了一个包装函数。这就像当坏人在电影中承诺不杀人并命令他的心腹杀死他们时一样。

那些多余的 const 只值一个电影坏蛋的承诺。


但是说谎的能力变得更糟了:

我已经了解到,您可以通过使用虚假 const 使标头(声明)和代码(定义)中的 const 不匹配。const-happy 的拥护者声称这是一件好事,因为它允许您仅将 const 放在定义中。

// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }

但是,反之亦然……您只能在声明中放置虚假的 const 并在定义中忽略它。这只会使 API 中多余的 const 变得更加可怕,而且是可怕的谎言——请看这个例子:

struct foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

所有多余的 const 实际上所做的只是通过强制实现者在想要更改变量或通过非 const 引用传递变量时使用另一个本地副本或包装函数来降低实现者的代码的可读性。

看看这个例子。哪个更具可读性?很明显,第二个函数中额外变量的唯一原因是因为某些 API 设计人员投入了多余的 const 吗?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

希望我们在这里学到了一些东西。多余的 const 是一个 API 杂乱无章的讨厌东西,一个烦人的唠叨,一个肤浅而毫无意义的承诺,一个不必要的障碍,并且偶尔会导致非常危险的错误。

于 2012-06-14T15:26:34.767 回答
39

const 应该是 C++ 中的默认值。像这样 :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable
于 2008-09-23T11:43:18.390 回答
24

当我以编写 C++ 为生时,我尽我所能。使用 const 是帮助编译器帮助您的好方法。例如,对您的方法返回值进行 const-ing 可以使您免于打字错误,例如:

foo() = 42

当你的意思是:

foo() == 42

如果 foo() 被定义为返回一个非常量引用:

int& foo() { /* ... */ }

编译器很乐意让你为函数调用返回的匿名临时赋值。使其成为常量:

const int& foo() { /* ... */ }

消除了这种可能性。

于 2008-09-22T22:07:09.443 回答
15

在 comp.lang.c++.moderated here上的旧“本周大师”文章中对此主题进行了很好的讨论。

相应的 GOTW 文章可在 Herb Sutter 的网站上找到

于 2009-05-04T22:21:53.857 回答
10

1. 基于我的评估的最佳答案:

根据我的评估,@Adisak的答案是这里的最佳答案。请注意,这个答案部分是最好的,因为除了使用合理且经过深思熟虑的逻辑之外,它也是最可靠的真实代码示例支持。

2.我自己的话(同意最佳答案):

  1. 对于按值传递,添加const. 它所做的只是:
    1. 限制实现者每次想要更改源代码中的输入参数时都必须制作副本(这种更改无论如何都不会产生副作用,因为传入的内容已经是副本,因为它是按值传递的)。并且经常使用更改按值传递的输入参数来实现该功能,因此const到处添加可能会阻碍这一点。
    2. 添加const不必要的consts 会使代码到处乱七八糟,将注意力从const真正需要安全代码的 s 上转移开。
  2. 但是,在处理指针引用const时,在需要时非常重要,并且必须使用,因为它可以防止函数外部持续更改带来的不良副作用,因此当参数仅作为输入时,每个指针或引用都必须使用,const不是输出。const 仅对通过引用或指针传递的参数使用还有一个额外的好处,那就是让哪些参数是指针或引用非常明显。伸出手说“小心!const旁边的任何参数都是引用或指针!”是另一回事。
  3. 我上面所描述的经常是在我工作过的专业软件组织中达成的共识,并且被认为是最佳实践。有时,规则甚至是严格的:“永远不要对按值传递的参数使用 const,但如果它们只是输入,则始终对通过引用或指针传递的参数使用它。”

3.谷歌的话(同意我的最佳答案):

(来自“谷歌 C++ 风格指南”)

对于按值传递的函数参数,const 对调用者没有影响,因此不建议在函数声明中使用。参见TotW #109

既不鼓励也不鼓励对局部变量使用 const。

来源:Google C++ 样式指南的“使用 const”部分:https ://google.github.io/styleguide/cppguide.html#Use_of_const 。这实际上是一个非常有价值的部分,因此请阅读整个部分。

请注意,“TotW #109”代表“Tip of the Week #109: Meaningful constin Function Declarations”,也是一本有用的读物​​。它提供的信息更多,规定性更少,并且基于上下文出现const上面引用的 Google C++ 样式指南规则之前,但由于它提供的清晰性,const上面引用的规则被添加到 Google C++时尚指南。

另请注意,即使我在此处引用 Google C++ 样式指南来捍卫我的立场,但这并不意味着我始终遵循指南或始终建议遵循指南。他们推荐的一些东西很奇怪,例如他们的kDaysInAWeek风格命名约定 "Constant Names"然而,当世界上最成功和最有影响力的技术和软件公司之一使用与我和@Adisak 等其他人一样的理由来支持我们在这个问题上的观点时,指出它仍然是有用和相关的。

4. Clang 的 linterclang-tidy有一些选项:

A. 还值得注意的是,Clang 的 linterclang-tidy有一个选项,readability-avoid-const-params-in-decls此处描述,以支持在代码库中强制执行使用const传递值函数参数

检查函数声明是否具有顶级 const 参数。

声明中的 const 值不会影响函数的签名,因此不应将它们放在那里。

例子:

void f(const string);   // Bad: const is top level.
void f(const string&);  // Good: const is not top level.

为了完整和清晰,我添加了另外两个示例:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

B. 它也有这个选项:readability-const-return-type- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

5. 我对此事的风格指南措辞的务实方法:

我只需将其复制并粘贴到我的样式指南中:

[复制/粘贴开始]

  1. const当它们的内容(它们指向的内容)不打算更改时,始终使用通过引用或指针传递的函数参数。这样,当一个通过引用或指针传递的变量被期望被改变时,它就变得很明显了,因为它会缺少const. 在这个用例const中,可以防止函数之外的意外副作用。
  2. 建议在函数参数上使用const值传递,因为const对调用者没有影响:即使在函数中改变了变量也不会在函数外产生副作用。有关其他理由和见解,请参阅以下资源:
    1. “Google C++ 风格指南”“const 的使用”部分
    2. “本周提示 #109:const函数声明中的意义”
    3. Adisak 的 Stack Overflow 上关于“函数参数使用 'const' 的答案”
  3. "永远不要在不是定义的声明中对函数参数使用顶级const[即:const值传递的参数] (并注意不要复制/粘贴无意义的)。它是无意义的,编译器会忽略它,这是视觉噪音,它可能会误导读者”(https://abseil.io/tips/109,强调补充)。const
  4. 唯一const对编译有影响的限定符是那些放在函数定义中的限定符,而不是那些在函数的前向声明中的限定符,例如在头文件中的函数(方法)声明中。
  5. 永远不要在函数返回的值上使用顶级const[ie: conston variables passed by value ] 。
  6. 使用const函数返回的指针或引用取决于实现者,因为它有时很有用。
  7. TODO:使用以下clang-tidy选项强制执行上述某些操作:
  8. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
  9. https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

下面是一些代码示例来演示上述const规则:

const参数示例:(
有些是从这里借来的)

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

const返回类型示例:(
有些是从这里借来的)

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

[复制/粘贴结束]

关键词:const函数参数的使用;编码标准;C 和 C++ 编码标准;编码指南;最佳实践;代码标准;常量返回值

于 2020-03-23T23:33:47.380 回答
9

我在作为引用(或指针)的函数参数上使用 const,这些引用(或指针)只是 [in] 数据并且不会被函数修改。意思是,当使用引用的目的是避免复制数据并且不允许更改传递的参数时。

在您的示例中将 const 放在布尔 b 参数上只会对实现施加约束,并且不会为类的接口做出贡献(尽管通常建议不要更改参数)。

函数签名为

void foo(int a);

void foo(const int a);

是一样的,这解释了你的 .c 和 .h

阿萨夫

于 2008-09-22T20:15:24.767 回答
9

我说 const 你的值参数。

考虑这个错误的功能:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

如果 number 参数是 const,编译器将停止并警告我们该错误。

于 2008-11-14T13:38:17.597 回答
6

如果您使用->*or.*运算符,这是必须的。

它会阻止你写类似的东西

void foo(Bar *p) { if (++p->*member > 0) { ... } }

我几乎现在就这样做了,这可能不会像你想要的那样。

我想说的是

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

如果我在andconst之间放了一个,编译器会告诉我的。Bar *p

于 2012-07-24T00:45:03.683 回答
5

啊,一个艰难的。一方面,声明是一种契约,按值传递 const 参数确实没有意义。另一方面,如果您查看函数实现,如果您声明一个参数常量,就会给编译器更多优化的机会。

于 2008-09-22T20:18:31.420 回答
5

当参数按值传递时, const 毫无意义,因为您不会修改调用者的对象。

通过引用传递时应该首选 const,除非函数的目的是修改传递的值。

最后,不修改当前对象 (this) 的函数可以并且可能应该声明为 const。下面是一个例子:

int SomeClass::GetValue() const {return m_internalValue;}

这是一个不修改应用此调用的对象的承诺。换句话说,您可以调用:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

如果函数不是 const,这将导致编译器警告。

于 2008-09-22T20:40:11.167 回答
5

标记值参数'const'绝对是一个主观的事情。

但是,我实际上更喜欢将值参数标记为 const,就像在您的示例中一样。

void func(const int n, const long l) { /* ... */ }

对我来说,价值清楚地表明函数参数值永远不会被函数改变。它们在开始时和结束时将具有相同的值。对我来说,这是保持非常函数式编程风格的一部分。

对于一个简短的函数,可以说在那里有“const”是浪费时间/空间,因为通常很明显,函数没有修改参数。

但是,对于较大的函数,它是一种实现文档的形式,并且由编译器强制执行。

我可以肯定,如果我用“n”和“l”进行一些计算,我可以重构/移动该计算,而不必担心得到不同的结果,因为我错过了一个或两个都被改变的地方。

由于它是一个实现细节,因此您不需要在标头中声明值参数 const,就像您不需要声明与实现使用的名称相同的函数参数一样。

于 2008-09-22T22:58:07.060 回答
4

可能这不是一个有效的论点。但是如果我们在函数编译器中增加一个 const 变量的值,将会给我们一个错误:“ error: increment of read-only parameter ”。所以这意味着我们可以使用 const 关键字来防止意外修改函数内部的变量(我们不应该/只读)。所以如果我们在编译时不小心做了,编译器会让我们知道。如果您不是唯一从事此项目的人,这一点尤其重要。

于 2015-04-03T21:21:34.743 回答
3

我倾向于尽可能使用 const 。(或目标语言的其他适当关键字。)我这样做纯粹是因为它允许编译器进行额外的优化,否则它无法进行。因为我不知道这些优化可能是什么,所以我总是这样做,即使它看起来很傻。

据我所知,编译器很可能会看到一个 const value 参数,然后说:“嘿,这个函数无论如何都不会修改它,所以我可以通过引用传递并节省一些时钟周期。” 我不认为它会做这样的事情,因为它改变了函数签名,但它说明了这一点。也许它做了一些不同的堆栈操作或其他什么......关键是,我不知道,但我知道试图比编译器更聪明只会让我感到羞耻。

C++ 有一些额外的包袱,带有 const-correctness 的想法,所以它变得更加重要。

于 2008-09-22T20:36:13.377 回答
2

在您提到的情况下,它不会影响您的 API 的调用者,这就是为什么通常不这样做(并且在标题中没有必要)。它只会影响你的函数的实现。

这并不是一件特别糟糕的事情,但是考虑到它不会影响您的 API,并且它增加了类型,因此它的好处并不是那么好,因此通常不会这样做。

于 2008-09-22T20:17:14.527 回答
2

我可以使用 const 。参数的 const 意味着它们不应该改变它们的值。这在通过引用传递时特别有价值。const for function 声明该函数不应更改类成员。

于 2008-09-22T20:22:42.097 回答
2

我不将 const 用于传递值的参数。调用者不在乎你是否修改参数,这是一个实现细节。

真正重要的是如果方法不修改其实例,则将它们标记为 const。边做边做,否则你可能会得到很多 const_cast<> 或者你可能会发现标记一个方法 const 需要更改很多代码,因为它调用了其他应该标记为 const 的方法。

如果我不需要修改本地变量,我也倾向于标记它们。我相信它通过更容易识别“移动部件”使代码更容易理解。

于 2008-09-22T20:24:43.013 回答
2

关于编译器优化:http ://www.gotw.ca/gotw/081.htm

于 2009-05-05T21:53:39.297 回答
2

总结一下:

  • “通常 const 传递值是无用的,充其量是误导性的。” 从GOTW006
  • 但是您可以像处理变量一样将它们添加到 .cpp 中。
  • 请注意,标准库不使用 const。例如std::vector::at(size_type pos)。对标准库足够好的东西对我也有好处。
于 2017-07-26T09:36:52.503 回答
1

如果参数是按值传递的(并且不是引用),通常参数是否声明为 const 并没有太大区别(除非它包含引用成员——对于内置类型来说不是问题)。如果参数是引用或指针,通常最好保护引用/指向的内存,而不是指针本身(我认为您不能将引用本身设为 const,这并不重要,因为您不能更改裁判) . 保护一切你可以作为 const 的东西似乎是个好主意。如果参数只是 POD(包括内置类型)并且它们没有机会沿着道路进一步更改(例如,在您的示例中为 bool 参数),您可以省略它而不必担心出错。

我不知道 .h/.cpp 文件声明的区别,但它确实有些道理。在机器代码级别,没有什么是“const”,因此如果将函数(在 .h 中)声明为非 const,则代码与将其声明为 const 相同(抛开优化)。但是,它可以帮助您让编译器知道您不会在函数 (.ccp) 的实现中更改变量的值。当您从允许更改的接口继承时,它可能会派上用场,但您不需要更改参数来实现所需的功能。

于 2008-09-22T20:27:59.043 回答
0

我不会把 const 放在这样的参数上——每个人都已经知道布尔值(而不是布尔值&)是常数,所以添加它会让人们认为“等等,什么?” 甚至是您通过引用传递参数。

于 2008-09-22T20:17:44.027 回答
0

使用 const 要记住的一点是,从一开始就将其设为 const 比稍后尝试将它们放入要容易得多。

当您希望某些内容保持不变时,请使用 const - 它是一个附加提示,描述了您的函数的作用和期望。我见过很多可以处理其中一些的 C API,尤其是那些接受 c-strings 的 API!

我更倾向于在 cpp 文件中省略 const 关键字而不是标题,但由于我倾向于剪切+粘贴它们,它们将被保留在两个地方。我不知道为什么编译器允许这样做,我猜它是编译器的事情。最佳实践绝对是将您的 const 关键字放在两个文件中。

于 2008-09-22T20:18:00.347 回答
0

您示例中的所有 const 都没有任何用途。默认情况下,C++ 是按值传递的,因此该函数获取这些整数和布尔值的副本。即使函数确实修改了它们,调用者的副本也不受影响。

所以我会避免额外的常量,因为

  • 他们是多余的
  • 他们把文本弄得乱七八糟
  • 它们阻止我在可能有用或有效的情况下更改传入的值。
于 2008-09-22T20:18:54.383 回答
0

由于参数是按值传递的,从调用函数的角度来看,是否指定 const 没有任何区别。将按值传递参数声明为 const 基本上没有任何意义。

于 2008-09-23T11:37:48.497 回答
-1

确实没有理由将值参数设为“const”,因为该函数无论如何只能修改变量的副本。

使用“const”的原因是如果你通过引用传递更大的东西(例如一个有很多成员的结构),在这种情况下它确保函数不能修改它;或者更确切地说,如果您尝试以传统方式修改它,编译器会抱怨。它可以防止它被意外修改。

于 2008-09-22T20:19:35.553 回答
-1

const 参数仅在参数通过引用(即引用或指针)传递时才有用。当编译器看到一个 const 参数时,它会确保参数中使用的变量在函数体中没有被修改。为什么有人想将按值参数设为常量?:-)

于 2008-09-22T20:27:49.400 回答
-1

我知道这个问题“有点”过时了,但是当我遇到它时,其他人将来也可能会这样做......我仍然怀疑这个可怜的家伙会在这里列出来阅读我的评论:)

在我看来,我们仍然过于局限于 C 风格的思维方式。在 OOP 范式中,我们玩弄的是对象,而不是类型。const 对象在概念上可能与非常量对象不同,特别是在逻辑常量的意义上(与按位常量相反)。因此,即使函数参数的 const 正确性(可能)在 POD 的情况下过于谨慎,但在对象的情况下并非如此。如果一个函数与一个 const 对象一起工作,它应该这样说。考虑以下代码片段

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

ps.:您可能会争辩说 (const) 引用在这里更合适,并给您相同的行为。嗯,对。只是给出与我在其他地方看到的不同的图片......

于 2015-04-08T09:14:41.037 回答
-1

作为需要使用具有 50 多个公开函数的 C++ 程序以及偶尔使用 const 限定符的 .h 文件的 VB.NET 程序员,很难知道何时使用 ByRef 或 ByVal 访问变量。

当然,程序会通过在您出错的那一行生成异常错误来告诉您,但接下来您需要猜测 2-10 个参数中的哪一个是错误的。

所以现在我有一个令人反感的任务,试图说服开发人员他们应该真正定义他们的变量(在 .h 文件中),以一种允许轻松创建所有 VB.NET 函数定义的自动化方法的方式。然后他们会沾沾自喜地说:“阅读……文档。”

我编写了一个解析 .h 文件并创建所有 Declare Function 命令的 awk 脚本,但没有指示哪些变量是 R/O 还是 R/W,它只完成了一半的工作。

编辑:

在另一位用户的鼓励下,我添加了以下内容;

这是(IMO)格式不正确的 .h 条目的示例;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

我的脚本生成的 VB;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

请注意第一个参数上缺少的“const”。没有它,程序(或其他开发人员)就不知道第一个参数应该传递“ByVal”。通过添加“const”,它可以使 .h 文件自我记录,以便使用其他语言的开发人员可以轻松编写工作代码。

于 2017-05-28T14:13:36.293 回答