`
hqs7636
  • 浏览: 220346 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

常量和不变量 Const and Invariant 2.014

阅读更多
请参考: D 2.0 Const/Final/Invariant 概念简介
http://dolive.iteye.com/admin/blogs/201374

这一篇1.028里没有

When examining a data structure or interface, it is very helpful to be able to easily tell which data can be expected to not change, which data might change, and who may change that data. This is done with the aid of the language typing system. Data can be marked as const or invariant, with the default being changeable (or mutable).

invariant applies to data that cannot change. Invariant data values, once constructed, remain the same for the duration of the program's execution. Invariant data can be placed in ROM (Read Only Memory) or in memory pages marked by the hardware as read only. Since invariant data does not change, it enables many opportunities for program optimization, and has applications in functional style programming.

const applies to data that cannot be changed by the const reference to that data. It may, however, be changed by another reference to that same data. Const finds applications in passing data through interfaces that promise not to modify them.

Both invariant and const are transitive, which means that any data reachable through an invariant reference is also invariant, and likewise for const.

Invariant Storage Class
The simplest invariant declarations use it as a storage class. It can be used to declare manifest constants.

invariant int x = 3; // x is set to 3
x = 4; // error, x is invariant
char[x] s; // s is an array of 3 char's
The type can be inferred from the initializer:

invariant y = 4; // y is of type int
y = 5; // error, y is invariant
If the initializer is not present, the invariant can be initialized from the corresponding constructor:

invariant int z;
void test()
{
    z = 3; // error, z is invariant
}
static this()
{
    z = 3;    // ok, can set invariant that doesn't have
              // static initializer
}
The initializer for a non-local invariant declaration must be evaluatable at compile time:

int foo(int f) { return f * 3; }
int i = 5;
invariant x = 3 * 4;      // ok, 12
invariant y = i + 1;      // error, cannot evaluate at compile time
invariant z = foo(2) + 1; // ok, foo(2) can be evaluated at compile time, 7
The initializer for a non-static local invariant declaration is evaluated at compile time:

int foo(int f)
{
  invariant x = f + 1;  // evaluated at run time
  x = 3;                // error, x is invariant
}
Because invariant is transitive, data referred to by an invariant is also invariant:

invariant char[] s = "foo";
s[0] = 'a';  // error, s refers to invariant data
s = "bar";   // error, s is invariant
Invariant declarations can appear as lvalues, i.e. they can have their address taken, and occupy storage.

Const Storage Class
A const declaration is exactly like an invariant declaration, with the following differences:

Any data referenced by the const declaration cannot be changed from the const declaration, but it might be changed by other references to the same data.
The type of a const declaration is itself const.
Invariant Type
Data that will never change its value can be typed as invariant. The invariant keyword can be used as a type constructor:

invariant(char)[] s = "hello";
The invariant applies to the type within the following parentheses. So, while s can be assigned new values, the contents of s[] cannot be:

s[0] = 'b';  // error, s[] is invariant
s = null;    // ok, s itself is not invariant
Invariantness is transitive, meaning it applies to anything that can be referenced from the invariant type:

invariant(char*)** p = ...;
p = ...;        // ok, p is not invariant
*p = ...;       // ok, *p is not invariant
**p = ...;      // error, **p is invariant
***p = ...;     // error, ***p is invariant
Invariant used as a storage class is equivalent to using invariant as a type constructor for the entire type of a declaration:

invariant int x = 3;   // x is typed as invariant(int)
invariant(int) y = 3;  // y is invariant
Creating Invariant Data
The first way is to use a literal that is already invariant, such as string literals. String literals are always invariant.

auto s = "hello";   // s is invariant(char)[5]
char[] p = "world"; // error, cannot implicitly convert invariant
    // to mutable
The second way is to cast data to invariant. When doing so, it is up to the programmer to ensure that no other mutable references to the same data exist.

char[] s = ...;
invariant(char)[] p = cast(invariant)s;     // undefined behavior
invariant(char)[] p = cast(invariant)s.dup; // ok, unique reference
The .idup property is a convenient way to create an invariant copy of an array:

auto p = s.idup;
p[0] = ...;   // error, p[] is invariant
Removing Invariant With A Cast
The invariant type can be removed with a cast:

invariant int* p = ...;
int* q = cast(int*)p;
This does not mean, however, that one can change the data:

*q = 3; // allowed by compiler, but result is undefined behavior
The ability to cast away invariant-correctness is necessary in some cases where the static typing is incorrect and not fixable, such as when referencing code in a library one cannot change. Casting is, as always, a blunt and effective instrument, and when using it to cast away invariant-correctness, one must assume the responsibility to ensure the invariantness of the data, as the compiler will no longer be able to statically do so.

Invariant Member Functions
Invariant member functions are guaranteed that the object and anything referred to by the this reference is invariant. They are declared as:

struct S
{   int x;

    invariant void foo()
    {
x = 4;     // error, x is invariant
this.x = 4; // error, x is invariant
    }
}
Const Type
Const types are like invariant types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.

Const Member Functions
Const member functions are functions that are not allowed to change any part of the object through the member function's this reference.

Implicit Conversions
Mutable and invariant types can be implicitly converted to const. Mutable types cannot be implicitly converted to invariant, and vice versa.

Comparing D Invariant and Const with C++ Const
Const, Invariant Comparison Feature D C++98
const keyword Yes Yes
invariant keyword Yes No
const notation Functional:
//ptr to const ptr to const int
const(int*)* p;
Postfix:
//ptr to const ptr to const int
const int *const *p;

transitive const Yes:
//const ptr to const ptr to const int
const int** p;
**p = 3; // error
No:
// const ptr to ptr to int
int** const p;
**p = 3;    // ok

cast away const Yes:
// ptr to const int
const(int)* p;
int* q = cast(int*)p; // ok
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p; //ok

modification after casting away const No:
// ptr to const int
const(int)* p;
int* q = cast(int*)p;
*q = 3;   // undefined behavior
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p;
*q = 3;   // ok

overloading of top level const Yes:
void foo(int x);
void foo(const int x);  //ok
No:
void foo(int x);
void foo(const int x);  //error

aliasing of const with mutable Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);

aliasing of invariant with mutable Yes:
void foo(invariant int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;  // undefined behavior
   bar(*x); // bar(??)
}
...
int i = 3;
foo(cast(invariant)&i, &i);
No invariants
type of string literal invariant(char)[] const char*
implicit conversion of string literal to non-const not allowed allowed, but deprecated


分享到:
评论

相关推荐

    常量支持库1.6版(const.fne).rar

    本文将详细解析易语言常量支持库1.6版(const.fne)中的核心概念和使用方法。 常量,顾名思义,是在程序运行过程中不可更改的值。在易语言中,常量库是预先定义的一系列固定不变的数值或字符串,它们代表了特定的意义...

    易语言常量支持库const.fne const_static.lib v1.6#8版(静态版)

    "易语言常量支持库const.fne const_static.lib v1.6#8版(静态版)"是专为易语言设计的一个扩展库,它提供了丰富的常量支持,增强易语言在编写程序时的表达能力和效率。 常量在编程中扮演着重要的角色,它们是不可...

    2、C++中const变量.docx

    2. const变量的特点 C++中的const变量具有以下特点: * const变量一旦被定义,不能被改变。 * const变量可以用来定义数组。 * const变量可以用来作为函数参数传递。 * const变量可以用来作为返回值类型。 3. ...

    const_Types2.rar_V2

    8. interrupt.h:中断处理相关的头文件,包含中断处理函数的声明和常量定义。 从这些文件中,我们可以推测这个项目可能在改进内核对TIOCGETP和TIOCSETP的支持,同时优化中断处理机制,特别是对于32位系统和64位整数...

    精彩编程与编程技巧-软件工程篇-Const与#Const的对比...

    `Const` 是用来声明编译时常量的关键字,这意味着一旦一个变量被用 `Const` 声明,它的值就不能在程序运行过程中改变。这是因为在编译阶段,编译器会将所有对这个常量的引用替换为常量的实际值。例如: ```vb Const...

    c语言const程序设计语言.pdf

    const在C++中是一个非常重要的限定符,用于声明一个变量为常量,即该变量的值在初始化后不能被修改。该部分内容将详细介绍const在C++中的使用场景和注意事项。 首先,文档提到了const常量的声明方式。例如,可以...

    全局变量、extern、static、const区别与联系.doc

    C++知识点: 全局变量、extern、static、const区别与联系.doc

    const 修饰成员函数.zip

    在C++编程语言中,`const`关键字是一个非常重要的元素,它被广泛用于声明常量、定义常量指针和常量引用,以及修饰成员函数。`const`修饰成员函数是一种特殊的用法,用于限制成员函数对对象状态的修改。在本教程中,...

    c++程序const分配内存情况.zip

    总的来说,`const`在C++中提供了对变量、指针、成员函数等的常量性约束,有助于提高代码的稳定性和可读性。在内存分配上,`const`主要影响的是变量的可修改性,而不是直接影响内存的栈和堆分配,但通过`const`可以更...

    const T vs. T const

    首先,const关键字可以应用于变量、函数参数、返回值以及类的成员函数等,表示"常量"或"不可变"的意思。当const修饰变量时,该变量的值不允许被修改;当const修饰函数参数时,表示在函数内部不会修改该参数的值;当...

    VC++ string_format(const char* format, ...)

    能够按照格式化输出字符串数据,长度不受限制,亲测十几兆都正常。 #include using namespace std;

    const 用法总结.

    在编程语言中,`const` 是一个非常重要的关键字,它用于声明常量或者定义只读变量。`const` 的用法在多种编程语言中都有所体现,如 C++、C#、JavaScript 等,虽然具体语法和特性可能有所不同,但核心概念是相似的:...

    例1_1变量和常量.rar_变量_常量

    在编程领域,变量和常量是基本且至关重要的概念,特别是在Delphi这样的面向对象的编程语言中。Delphi教程中的这个例题代码着重讲解了如何使用变量和常量,让我们一起深入探讨这两个主题。 首先,变量是存储数据的...

    VC++中常量与静态变量及其存储位置的定义共2页.pdf

    在VC++编程环境中,常量和静态变量是两种重要的数据类型,它们在程序设计中扮演着不可或缺的角色。本文将深入探讨这两种变量的概念、特点、存储位置以及在VC++中的使用。 首先,常量(Constant)是指在程序执行过程...

    常量支持库1.6版(const.fne)-易语言

    常量支持库1.6版(const.fne)是易语言的一个重要扩展,专为增强易语言的功能而设计,特别是在处理常量方面。常量在编程中扮演着不可或缺的角色,它们是不可变的值,一旦被定义,就不能在程序运行过程中改变。 这个...

    VB程序设计初步 常量变量和赋值语句PPT课件.pptx

    VB程序设计初步常量变量和赋值语句PPT课件 VB程序设计初步中,常量和变量是两个基本概念。常量是程序设计过程中值不变的存储单元或数据,例如圆周率pi=3.14,重力加速度g=9.8。变量是用来表示数据的存储区域,在...

    comsol内置参数变量函数[参照].pdf

    空间坐标变量和因变量是 COMSOL 中的一些特殊变量,这些变量基于空间维度和所选物理场的变量,有默认的名称。 内置数学函数包括: * abs:绝对值 * acos:反余弦 * acosh:反双曲余弦 * acot:反余切 * acoth:反...

    常量与变量教学设计说明.docx

    - 通过程序实例,如计算圆面积、华氏温度转摄氏温度和计算本息和,我们可以看到如何在C语言中声明变量和使用常量。例如: ```c #include "stdio.h" int main() { float radius, area; printf("Input radius: ...

    const的使用.txt

    `const`关键字用于声明一个不可变的变量或指针指向的值不可改变。它可以被放在数据类型的前面或后面,但其意义有所不同。 ##### 示例1:常量定义 ```cpp const float pi = 3.1415926; ``` 这行代码定义了一个名为`...

    C语言中CONST的用法.pdf

    首先,`const`的基本概念是声明一个常量,即一个不能被修改的变量。常量可以是基本数据类型,如整型、浮点型等,也可以是数组、对象或指针。通过`const`定义的常量具有不可变性,这有助于确保代码的稳定性和正确性。...

Global site tag (gtag.js) - Google Analytics