한국리눅스유저그룹 위키페이지- LUG KOREA
Kernel News | GNOME News | KDE News | linux.kernel | comp.lang.c++ | wxWidgets GUI | comp.lang.python
 

In this article, I give you programming tips that can improve your C++ code. I will cover use of parentheses, long expressions, modifying objects, and more. By the time I'm done, you will hopefully have learned a few ways to make your code faster as well as easier to understand and maintain.

이 문서에 C++ 코드를 향상시킬 수 있는 팁을 적어둔다. 괄호와 긴 표현식, 오브젝트 수정등등. 다 읽고 나면 도움이 될것 같다.

C++ Fundamentals

Use of parentheses

Consider this expression without parentheses:

괄호가 없는 표현식을 생각해 보자:

a * b + c / d – 4

and the equivalent with parentheses:

그리고 괄호를 넣어보자:

(a * b) + (c / d) – 4

Both expressions perform exactly the same computation, but the meaning of the second one is clearer, since parentheses are used.

두 표현식은 같은 연산을 수행한다. 하지만 두 번째가 명확한 의미를 전달한다. 그래서 괄호를 사용한다.

Expressions (like the two above) are evaluated by following the rules of precedence. The above expressions are the same. So from a technical point of view, you do not need parentheses. However, including parentheses makes the order of evaluation explicit to the person maintaining your code (even you).

표현식은 우선순위 규칙에 따라 진행된다. 위의 표현식들은 같다. 기술적인 면에서 괄호를 사용할 필요는 없지만, 괄호를 사용하면 코드를 유지보수하는 사람에게 명확한 의미를 전달해 줄 것이다.

Long expressions (Style)

We often need to write long expressions that will not fit on one line of the screen. For example, the expression

cout « Mass « “grams of a hydrocarbonnwith “« CarbonAtoms « “ carbon atom(s) and “ « HydrogenAtoms « “ hydrogen atom(s)ncontains “ « Molecules « “molecules” « endl;

is quite long and will not fit on one line of the screen. A good way to break a long expression into a multiline expression is to use continuation lines. These lines should always begin with an operator and be indented one space. Both of these serve to signal the reader that the line is a continuation of the previous line. So the above example can be written as follows:

cout « Mass « “grams of a hydrocarbonnwith “« CarbonAtoms

« “ carbon atom(s) and “ « HydrogenAtoms « “ hydrogen atom(s)ncontains “

« Molecules « “molecules” « endl;

As another example, the expression

((Xcoord1 – Ycoord1) / 2 ) * Distance1 + ((Xcoord2 – Ycoord2) /

2) * Distance2;

can be better written as

((XCoord1 – Ycoord1) / 2 ) * Distance1

+ ((Xcoord2 – Ycoord2) / 2) * Distance2;

Speed versus clarity and correctness

One rule of thumb in programming is that 90 percent of a program’s running time is spent on 10 percent of the code. So without some idea of where a program spends most of its time, most changes to a program to speed it up will have little or no effect on the overall running time. While speed is important, clarity (presentation of the code) and correctness are always more important. We should never sacrifice clarity and correctness for speed.

Hot spots are where a program spends most of its time. If speed becomes an issue, a more effective approach is to complete the writing of the program and then order a tool which can be used to identify the hot spots of the program. The hot spots can then be tuned (recoded) to reduce the running time of the program.

Modifying Objects

Increment and decrement operators (style)

Always use increment and decrement operators to reduce the length of your code. This also portrays you as a mature programmer.

So for example, you should write

i++ or ++i

instead of

i=i+1

or write

i– or –i

instead of

i=i-1

where i is a C++ variable.

Watch out for operator precedence on long expressions.

Function Usage Basics and Libraries

Controlling the evaluation of assert invocations

The default behavior of an assert invocation is to evaluate assertions. The macro NDEBUG must be undefined for the expression in an assert invocation to be evaluated. Through the use of the following preprocessor statement, the evaluation of subsequent assertions can be turned off.

#define NDEBUG

In some cases, evaluation of assertions can be turned on again through the use of the following preprocessor statement:

#undef NDEBUG

This process works because the actions that an assert invocation performs are nested within a conditional evaluation directive that checks whether NDEBUG is defined. It is a good practice to include the definition of NDEBUG at the start of a program that is distributed to users.

Safe input type

Professional software normally extracts its input in character form. This input is then validated and converted to the desired form (e.g. int). This provides a safe way of extracting data. If you do not respect this, you may suffer from the following consequence: if an int is required and the user accidentally types in a non-digit, the program might terminate with an error message that the user does not understand.

Advanced Parameter Passing

Efficiency in Using Constant Reference Parameter

If you pass an object by value to a function, a copy of the object is first made and then passed to the called function. For large objects, copying can add considerable overhead to the program and may also adversely affect the performance of the program. For such objects, you can obtain efficiency and retain safety by passing the object as a constant reference parameter, such as the following:

ReturnValue functionName(const type &objectName)

The const modifier ensures that the called function does not modify the actual object.

Abstract Data Types

Developing object-oriented programs is typically simpler than developing procedure oriented programs. For example, member functions generally have a smaller parameter list than non-member functions because there is no need to pass the data to member functions.

Since well-written member functions ensure that the data members are correctly initialized and updated, other program functions do not need to validate whether they are using proper object values. The access protection provided by encapsulation also ensures that clients use the public interface and not side effects of the library implementation that may continue as the implementation is modified over time.

Rule of minimality

The rule of minimality states that unless a behavior is needed, it should not be part of the Abstract Data Type. A corollary of this rule is the Class Minimality Principle, which states that if a function or operator can be defined such that it is not a member of the class, then do not make it a member. This practice makes a non-member function or operator generally independent of changes to the class’s implementation.

C++ Programming Tips - List

Character strings or string class strings

If you use the string class, you have a more extensive set of capabilities than if you use character strings.

Generic vector extraction

Consider the following:

Template (class T)

Void GetValues(vector<T> &A)

{

A.resize(0);

T Val;

While (cin » Val)

{

A.push_back(Val);

}

}

The syntax template <class T> indicates that what follows is a generic form. In this situation, the form of the function is given. This function template allows different functions to be instantiated based on the particular type of vector used as the actual parameter. For example, if we have the following definitions:

vector<int> X;

vector<float> Y;

the invocations

GetValues(X);

GetValues(Y);

cause functions

void GetValues(vector<int> &A)

{

A.resize(0);

int Val;

while (cin » Val)

{

A.push_back(Val);

}

}

void GetValues(vector<float> &A)

{

A.resize(0);

float Val;

while (cin » Val)

{

A.push_back(Val);

}

}

to be defined and invoked.

Accessing multidimensional arrays

Multidimensional arrays are stored in row-major order. Often contiguous sections of memory, called pages, are brought in with the expectation that values near a desired value are more likely to be referenced than values defined elsewhere in memory. Since a page is contiguous memory, it is more likely to contain a complete row than a complete column. So it is generally more efficient to process array elements row-by-row rather than column-by-column. This efficiency comes about in how memory values are brought into the central processing unit, as explained above.

Pointer strength

The ability to access and change the value of an object whose name is not part of the assignment statement is the feature that makes pointer objects so powerful. This capability is most often used for dynamic objects.

Inheritance: Using data member initialization list

There are two ways to initialize data members when implementing the constructor of a class. One way is to invoke the constructor for the data member via the data member initialization list. The other method is to invoke the data member’s mutator from within the body of the constructor. With the second method, the data member’s default constructor is invoked to construct an object with default values, then the mutator is called to overwrite the default values with initial values. Using the first method, the data member is constructed with the appropriate initial values. As you can see the second method is more efficient, because it is done during construction.

Templates and Polymorphism

Automatic subscript checking for vector elements and other list elements

The vector class template provides a member function, which is:

at().

The function expects an index value as its parameter, say i. If the index is valid (exists), a reference to the ith element of the vector is returned. Otherwise, an exception is generated; the program stops, giving an error message that the user does not understand. You can use inheritance to derive a class that overloads the subscript operators so that index checking is automatically performed in conjunction with the subscript operators. To solve this problem, a template class named protectVector is given below.

Template <class T>

class protectVector : public vector<T>

{

public:

protectVector() : vector<T>() {}

protectVector(int n) : vector<T>(n) {}

protectVector(int n, T v) : vector<T>(n,v) {}

T& operator[](int i)

{

return at(i);

}

const T& operator[](int i) const

{

return at(i);

}

};

Assume reuse

If you are defining a class, unless you know it can never serve as a base class for a derive class, give the class a virtual destructor. In this way, all derived destructors will also be virtual and then, whenever an object is deleted, the correct destructor will be invoked, regardless of the context.

 
cpp/tips.txt · 마지막 수정: 2008/07/17 12:27 작성자 multi
 
이 위키의 내용은 다음의 라이센스에 따릅니다 :CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki