c++ const用法 - 為什麼在方法或函數名之前和之後使用const關鍵字?




(5)

第一個const表示函數返回const T引用。

第二個說該方法不會改變對象的狀態。 即方法不會更改任何成員變量。

我的應用程序中有以下代碼。 為什麼我們使用const關鍵字和返回類型以及方法名稱之後?

const T& data() const { return data_; }

const T& data() const { return data_; }
^^^^^

意味著它將返回一個對Tconst引用(這裡是data_

Class c;
T& t = c.data()             // Not allowed.
const T& tc = c.data()      // OK.
const T& data() const { return data_; }
                ^^^^^

表示該函數不會修改該類的任何成員變量(除非該成員是mutable )。

void Class::data() const {
   this->data_ = ...;  // is not allowed here since data() is const (unless 'data_' is mutable)
   this->anything = ... // Not allowed unless the thing is 'mutable'
}

const T& data() const { return data_; }

成員函數之後的const表示數據是常量成員函數,並且在此成員函數中沒有數據成員被修改。

const返回類型表示將常量ref返回給T.


const (和volatile )限定符綁定到左側 。 這意味著const看到const ,它都會應用於它左側的標記。 但是有一個例外; 如果const的左邊沒有任何內容,那麼它就會綁定到右邊。 記住這些規則很重要。

在你的例子中,第一個const在它的左邊沒有任何東西,所以它綁定到右邊,即T 這意味著返回類型是對const T的引用。

第二個const確實有左邊的東西; 功能data() 。 這意味著const將綁定到函數,使其成為const函數。

最後,我們有一個const函數返回對const T的引用


TL; DR:改用__builtin內在函數。

我能夠通過使用__builtin_popcountll使用相同的彙編指令,但沒有錯誤的依賴性錯誤,使gcc 4.8.4(甚至gcc.godbolt.org上的4.7.3)為此生成最佳代碼。

我不是100%確定我的基準代碼,但objdump輸出似乎分享我的看法。 我使用一些其他技巧( ++i vs i++ )來讓編譯器在沒有任何movl指令的情況下展開循環(奇怪的行為,我必須說)。

結果:

Count: 20318230000  Elapsed: 0.411156 seconds   Speed: 25.503118 GB/s

基準代碼:

#include <stdint.h>
#include <stddef.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

uint64_t builtin_popcnt(const uint64_t* buf, size_t len){
  uint64_t cnt = 0;
  for(size_t i = 0; i < len; ++i){
    cnt += __builtin_popcountll(buf[i]);
  }
  return cnt;
}

int main(int argc, char** argv){
  if(argc != 2){
    printf("Usage: %s <buffer size in MB>\n", argv[0]);
    return -1;
  }
  uint64_t size = atol(argv[1]) << 20;
  uint64_t* buffer = (uint64_t*)malloc((size/8)*sizeof(*buffer));

  // Spoil copy-on-write memory allocation on *nix
  for (size_t i = 0; i < (size / 8); i++) {
    buffer[i] = random();
  }
  uint64_t count = 0;
  clock_t tic = clock();
  for(size_t i = 0; i < 10000; ++i){
    count += builtin_popcnt(buffer, size/8);
  }
  clock_t toc = clock();
  printf("Count: %lu\tElapsed: %f seconds\tSpeed: %f GB/s\n", count, (double)(toc - tic) / CLOCKS_PER_SEC, ((10000.0*size)/(((double)(toc - tic)*1e+9) / CLOCKS_PER_SEC)));
  return 0;
}

編譯選項:

gcc --std=gnu99 -mpopcnt -O3 -funroll-loops -march=native bench.c -o bench

GCC版本:

gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4

Linux內核版本:

3.19.0-58-generic

CPU信息:

processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 70
model name  : Intel(R) Core(TM) i7-4870HQ CPU @ 2.50 GHz
stepping    : 1
microcode   : 0xf
cpu MHz     : 2494.226
cache size  : 6144 KB
physical id : 0
siblings    : 1
core id     : 0
cpu cores   : 1
apicid      : 0
initial apicid  : 0
fpu     : yes
fpu_exception   : yes
cpuid level : 13
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc nopl xtopology nonstop_tsc eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm arat pln pts dtherm fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 invpcid xsaveopt
bugs        :
bogomips    : 4988.45
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:




c++