メンバ変数のconst
メンバ変数のconst
のように値を変更しない変数をクラス内で宣言したいです。
この場合aの初期化は
のようにコンストラクタでしないといけないです。
私がしたいのはインスタンスごとに初期値が異なるもののため
になります。
しかし、こうすると
のように配列宣言すると引数ありコンストラクタを呼べないので
aを初期化できなくなります。
なんとかaに値を入れる方法がないでしょうか?
constをやめればいつでも代入でできるため値をいれれますが
変更しない値なのでconstのほうがいいように思います。
また、上記の例では必要なかったのでメンバ変数は1つですが
作るものは10を超える予定のため、コンストラクタの引数で
のように書くよりは
のように見やすくひとつずつ代入のように値を入れていける方法が
いいです。
よい方法を教えて下さい。
この場合aの初期化は
のようにコンストラクタでしないといけないです。
私がしたいのはインスタンスごとに初期値が異なるもののため
になります。
しかし、こうすると
のように配列宣言すると引数ありコンストラクタを呼べないので
aを初期化できなくなります。
なんとかaに値を入れる方法がないでしょうか?
constをやめればいつでも代入でできるため値をいれれますが
変更しない値なのでconstのほうがいいように思います。
また、上記の例では必要なかったのでメンバ変数は1つですが
作るものは10を超える予定のため、コンストラクタの引数で
のように書くよりは
のように見やすくひとつずつ代入のように値を入れていける方法が
いいです。
よい方法を教えて下さい。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
やりたい事は、こういう事でしょうか?
代入に関しては、C++の文法の範囲で良い方法が思いつきませんでした。
[追記]C#なら出来ると思うのですが、C++/CLIは分かりません。
#include <iostream>
class A
{
const int a;
const int b;
public:
A( int arg_a,int arg_b ) : a( arg_a ), b( arg_b ) {};
void print() {
std::cout << a << "," << b << std::endl;
};
};
int main()
{
A a[3] = {A(10,2), A(5,5), A(3,2)};
for( int i = 0; i < 3 ; i++ ) {
a[i].print();
}
return 0;
}
[追記]C#なら出来ると思うのですが、C++/CLIは分かりません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
C++的に書くなら、まずデフォルトコンストラクタも書いときましょう。
まぁこれはいいとして、初期化、というかインスタンスの確保にplacement newを使いましょう。
んんー、placement newはヒープでは無く静的に配置されますから、動的な確保はいろいろアレですが、
定数をそれぞれ設定するって事はある程度数が予測できそうですからこんなんでいいんじゃないでしょうか
class A{
const int a;
public:
A() : a( 0 ) {} // デフォルトコンストラクタ。ダミーの初期化
A(int arg_a) : a(arg_a) {}
}
#include <new> // *
int main(){
A a[10];
// ループ使う場合
for( int i = 0; i < 10; ++i ){
new( a + i ) A( 100 );
}
// 等等
// 各々の場合
new( a + 0 ) A( 10 );
new( a + 1 ) A( 20 );
new( a + 2 ) A( 30 );
new( a + 3 ) A( 40 );
new( a + 4 ) A( 50 );
new( a + 5 ) A( 60 );
new( a + 6 ) A( 70 );
new( a + 7 ) A( 80 );
new( a + 8 ) A( 90 );
new( a + 9 ) A( 100 );
new( a + 10 ) A( 110 );
};
んんー、placement newはヒープでは無く静的に配置されますから、動的な確保はいろいろアレですが、
定数をそれぞれ設定するって事はある程度数が予測できそうですからこんなんでいいんじゃないでしょうか
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
C99なら のように書けますが、これはC++には実装されていませんから、残念ながらできません。
一つの案ですが、どうしてもメンバ変数をconstにしたくて、しかもメンバ変数名を指定しつつ初期値を書きたいなら、mapをコンストラクタに渡す、なんていうのはどうでしょうか。
#include <iostream>
#include <map>
#include <string>
#include <boost/any.hpp>
struct A
{
const int a1;
const std::string a2;
A(const std::map<std::string, boost::any>& init_values)
: a1(boost::any_cast<int>(init_values.at("a1"))),
a2(boost::any_cast<std::string>(init_values.at("a2")))
{}
};
int main()
{
A aa = {{
{"a1", 10},
{"a2", std::string("foo")}
}};
std::cout << aa.a1 << ", " << aa.a2 << std::endl;
}
Re: メンバ変数のconst
softya(ソフト屋)さん、loweさん、beatleさん 回答ありがとうございます。
softya(ソフト屋)さんの方法で配列の場合でも初期化することが出来ました。
と書けばよかったのですね
や とかかいてみてエラーだったのでできないと思いました。
C#なら代入のような書き方もできるのですか。
「C#なら出来ると思うのですが、C++/CLIは分かりません。」と書かれたのが
C#もC++/CLIも.NET系はわからないではなく、
C#では書けるがC++/CLIになるとわからないという
意味で書かれたのでしたら、
今回はC#でなくC++で作るため使えませんが気になるので
C#だとどうなるのかを教えてもらえますか?
loweさんのplacement newを使う方法でもできました。
こうすればnewを使っても->じゃなくて.を使えるのですね。
を並べるだけなので見やすいですがこの方法でも のように引数に並べて書くことになりますね。
beatleさん
Cでは書けたのですか。
しかし、クラスを使うためC++なんです。
せっかく代案をだしてくれたのですが、複雑そうなので今回は
代入のように書くのは諦め、
softya(ソフト屋)さんの方法かloweさんの方法にすることにします。
ありがとうございました。
もう一つ聞きたいのですが
intで宣言したものをあとからconstに変更する
とかいう裏技があったり・・はしませんか?
softya(ソフト屋)さんの方法で配列の場合でも初期化することが出来ました。
と書けばよかったのですね
や とかかいてみてエラーだったのでできないと思いました。
C#なら代入のような書き方もできるのですか。
「C#なら出来ると思うのですが、C++/CLIは分かりません。」と書かれたのが
C#もC++/CLIも.NET系はわからないではなく、
C#では書けるがC++/CLIになるとわからないという
意味で書かれたのでしたら、
今回はC#でなくC++で作るため使えませんが気になるので
C#だとどうなるのかを教えてもらえますか?
loweさんのplacement newを使う方法でもできました。
こうすればnewを使っても->じゃなくて.を使えるのですね。
を並べるだけなので見やすいですがこの方法でも のように引数に並べて書くことになりますね。
beatleさん
Cでは書けたのですか。
しかし、クラスを使うためC++なんです。
せっかく代案をだしてくれたのですが、複雑そうなので今回は
代入のように書くのは諦め、
softya(ソフト屋)さんの方法かloweさんの方法にすることにします。
ありがとうございました。
もう一つ聞きたいのですが
intで宣言したものをあとからconstに変更する
とかいう裏技があったり・・はしませんか?
Re: メンバ変数のconst
はい、placement newに渡しているのはポインタではなく参照だからです。zxzy さんが書きました: loweさんのplacement newを使う方法でもできました。
こうすればnewを使っても->じゃなくて.を使えるのですね。
そもそも、C++ではconstメンバというのは基本的にコンストラクタの“{”まででしか初期化できませんから、不可能です。
(まぁ無理やり変更することもできなくはないですが、それでは定数の意味を成しません。
聞いたことないですが多分無いんじゃないでしょうか・・・const intとintは別物でしょうからintで宣言したものをあとからconstに変更する
とかいう裏技があったり・・はしませんか?
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
リクエストのものです。VC#2010以降限定。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CScon
{
class A
{
readonly int a;
readonly int b;
public A(int arg_a=3, int arg_b=3)
{
a = arg_a;
b = arg_b;
}
public void print()
{
Console.Write("{0:d},{1:d}\n", a, b);
}
}
class Program
{
static void Main(string[] args)
{
A[] array = new A[3] { new A(0, 1), new A(arg_b: 2, arg_a: 15), new A(arg_b: 4, arg_a: 7) };
for (int i = 0; i < 3; i++)
{
array[i].print();
}
}
}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
loweさん
回答ありがとうございます。
やっぱりintをconst intにするなんて無理ですよね。
softya(ソフト屋) さん
C#版ありがとうございます。
constじゃなくread onlyを使うことでコンストラクタで
初期化できるようにしているのですね。
しかし、私がしたかったことは、
のように定数に直接数字をいれ、見やすくしたかったのです。
教えていただいた方法では と仮引数を代入し、 のように数字はコンストラクタの実引数に書いています。
配列の場合に引数ありコンストラクタを呼ぶ方法とC++で代入は無理とわかったので
これで解決としたいと思います。
回答していただいた方々ありがとうございました。
回答ありがとうございます。
やっぱりintをconst intにするなんて無理ですよね。
softya(ソフト屋) さん
C#版ありがとうございます。
constじゃなくread onlyを使うことでコンストラクタで
初期化できるようにしているのですね。
しかし、私がしたかったことは、
のように定数に直接数字をいれ、見やすくしたかったのです。
教えていただいた方法では と仮引数を代入し、 のように数字はコンストラクタの実引数に書いています。
配列の場合に引数ありコンストラクタを呼ぶ方法とC++で代入は無理とわかったので
これで解決としたいと思います。
回答していただいた方々ありがとうございました。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
arg_b: 4
は代入文と同じなので
A[] array = new A[3] {
new A(0, 1),
new A(
arg_a: 15
,arg_b: 2
),
new A(
arg_b: 4
,arg_a: 7
)
};
こう書けば、ほぼの狙い通りだと思うんですけどね。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CScon
{
class A
{
readonly int a;
readonly int b;
public A(int a = 3, int b = 3)
{
a = a;
b = b;
}
public void print()
{
Console.Write("{0:d},{1:d}\n", a, b);
}
}
class Program
{
static void Main(string[] args)
{
A[] array = new A[3] {
new A(
a: 0,
b: 1
),
new A(
a: 15,
b: 2
),
new A(
a: 7,
b: 4
)
};
for (int i = 0; i < 3; i++)
{
array[i].print();
}
}
}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
loweさんのplacement newを使う方法ですが、Aがコンストラクタとデストラクタで何かゴニョゴニョする場合だと問題になりませんかね。
配列確保したときにデフォルトコンストラクタが呼ばれますけど、デストラクタが呼ばれないままplacement newで上書きしてしまいますよね。
配列確保したときにデフォルトコンストラクタが呼ばれますけど、デストラクタが呼ばれないままplacement newで上書きしてしまいますよね。
Re: メンバ変数のconst
たぶんならないとおもいますよ。配列を確保していて、確かにデフォルトコンストラクタは呼ばれます。ISLe さんが書きました:loweさんのplacement newを使う方法ですが、Aがコンストラクタとデストラクタで何かゴニョゴニョする場合だと問題になりませんかね。
配列確保したときにデフォルトコンストラクタが呼ばれますけど、デストラクタが呼ばれないままplacement newで上書きしてしまいますよね。
が、別にAの配列じゃなくてchar[1000]とかでもいいわけです。この場合とにかく静的にメモリを確保する(追記:静的でなくてはならないわけではない)ことが重要なわけです。
デフォルトコンストラクタは前述のように“ダミー”です。そこでゴニョゴニョすることは想定してません、というかゴニョゴニョしたらそれこそダミーの意味がなくなります。あくまでも“Aのn個分のメモリを確保ね”とかけるように何も値の無いAをつくって上書きできるようにしてるだけですから。
デストラクタですが、ゴニョゴニョする場合は明示的に呼び出せばよい話です。今回は定数のお話なので触れませんでしたが。
おかしな事言ってたらすみません。
最後に編集したユーザー nullptr on 2012年3月08日(木) 11:01 [ 編集 2 回目 ]
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
>loweさん
それならダミーのコンストラクタの中身が空であることが重要ですよね。
ですが、わざわざ“ダミー”についてはどうでもよいというふうに断っていますよね。
なのでこのスレを読んだ人が「クラスの配列を宣言してplacement newで上書きするのはスタンダード」と誤解する可能性があるのではないかと思ったという次第です。
それならダミーのコンストラクタの中身が空であることが重要ですよね。
ですが、わざわざ“ダミー”についてはどうでもよいというふうに断っていますよね。
なのでこのスレを読んだ人が「クラスの配列を宣言してplacement newで上書きするのはスタンダード」と誤解する可能性があるのではないかと思ったという次第です。
Re: メンバ変数のconst
>ISLeさん
なるほど(´・ω・`)
定数の話だったので「どうでもいい」と表現したせいで誤解を招きそうですね・・
配慮が足りませんでした・・・すみません
なるほど(´・ω・`)
定数の話だったので「どうでもいい」と表現したせいで誤解を招きそうですね・・
配慮が足りませんでした・・・すみません
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
横槍をスミマセンがそれは微妙です。lowe さんが書きました: 別にAの配列じゃなくてchar[1000]とかでもいいわけです。とにかく静的にメモリを確保することが重要なわけです。
アライメントの問題があるので微妙というより基本的にはNGだと思います。
もちろんヒープから生のメモリを確保するのなら、そもそもデフォルトコンストラクタの問題も発生しないのですが。
ついでに空のコンストラクタを作ってしまうと、本来引数なしのコンストラクタを使いたくないのに
コンストラクタの引数なしでインスタンスが作成できてしまうようになるという問題も起きると思います。
結局、この場合プレースメントnew使えるのは
①そのクラスでユーザー定義の引数なしコンストラクタを必要としない。
②空の引数なしコンストラクタを作成することにより、引数なしでインスタンスが作成されてしまうことを許容する
ということですかね?
ところで、元も子もないことを言いますが、そもそも質問者さんは配列を使わないといけないのでしょうか?
配列にこだわらなくてstd::vector等を使ってもいいのなら、
reserveしてpush_backで加えていければほぼ要求通りのことが無理なくできると思うのですが・・・。
Re: メンバ変数のconst
すみません、アライメントの問題がある、とはどういうことでしょうか?GRAM さんが書きました:横槍をスミマセンがそれは微妙です。lowe さんが書きました: 別にAの配列じゃなくてchar[1000]とかでもいいわけです。とにかく静的にメモリを確保することが重要なわけです。
アライメントの問題があるので微妙というより基本的にはNGだと思います。
先の例はplacement newを使うという前提で組んでます、その際メモリをAの配列で確保するためにはデフォルトコンストラクタがいります。「引数なしのコンストラクタを使いたくない」などという条件は質問者様はおっしゃっていないですし。あと引数なしのコンストラクタを使いたくないのならcharとかなんなりでメモリ確保すればいいと思いますし(アライメントの問題というのを知りませんが・・・)。ついでに空のコンストラクタを作ってしまうと、本来引数なしのコンストラクタを使いたくないのに
コンストラクタの引数なしでインスタンスが作成できてしまうようになるという問題も起きると思います。
①は「この場合」では無いかと。②は確かにそうです。これもちゃんとハッキリ書くべきでした。本当にすみません。結局、この場合プレースメントnew使えるのは
①そのクラスでユーザー定義の引数なしコンストラクタを必要としない。
②空の引数なしコンストラクタを作成することにより、引数なしでインスタンスが作成されてしまうことを許容する
ということですかね?
【追記】
すみません今調べて知りました。m(_ _)m
【更に追記】
あとこれ「アラインメント」ですねすみませんm(_ _)m
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
解決済みとしたのに返信をいただきありがとうございます。
softya(ソフト屋)さん
を のようにかけば代入文のようにかけますね。
気づきませんでした。
ところで この部分のa=a;と書いても大丈夫なのでしょうか?
仮引数に代入はないし、readonly int のaにreadonly intのaを
入れるのも無意味なのでreadonly intのaに仮引数のaを入れるというのは
考えるとわかるのですがプログラムでこう書いても大丈夫なのでしょうか?
(エラーが出ないのかということと後で見た時なにしてるのかわかりづらく
なるため一般にこう書くべきでないなどの面で)
loweさん、ISLeさん、GRAMさん
複雑で完全に理解ができていないのですが
引数なしコンストラクタを必要としない場合でplacement newを絶対に使い
ダミーコンストラクタで引数なしのコンストラクタでインスタンスが作成
されてもいいのならplacement newを使ってもいいのでしょうか?
デストラクタについてですがplacement newを使うと静的になるので とすると の宣言したようになり、プログラム終了時までデストラクタが呼ばれなくなるので
自分で呼ぶ必要があるということでいいですか?
アライメントの問題というのがよくわからないのですが、
ダミーコンストラクタによるインスタンス生成時にクラスAの領域が確保されているので
placement newを使っても問題無いように思うのですけど。
placement newを使うとパディングが変わりAのサイズが変わったりするのですか?
また、ヒープから確保するとなると となってしまいますよね。
なので今回はplacement newを教えていただいたのだと思います。
配列を使わないといけないのかということですが、
Aのインスタンスを複数生成し、そのどれかのメンバの値を取り出す、書きこむ
ということをするときに配列でないと
のようにif文を書く必要があり、
配列にすると のようにかけるため配列を選びました。
std::vectorは使ったことがないのですが
配列より不便になるような欠点はないのですか?
できれば、上記の配列の例をstd::vectorにしたものを書いてもらえませんか?
softya(ソフト屋)さん
を のようにかけば代入文のようにかけますね。
気づきませんでした。
ところで この部分のa=a;と書いても大丈夫なのでしょうか?
仮引数に代入はないし、readonly int のaにreadonly intのaを
入れるのも無意味なのでreadonly intのaに仮引数のaを入れるというのは
考えるとわかるのですがプログラムでこう書いても大丈夫なのでしょうか?
(エラーが出ないのかということと後で見た時なにしてるのかわかりづらく
なるため一般にこう書くべきでないなどの面で)
loweさん、ISLeさん、GRAMさん
複雑で完全に理解ができていないのですが
引数なしコンストラクタを必要としない場合でplacement newを絶対に使い
ダミーコンストラクタで引数なしのコンストラクタでインスタンスが作成
されてもいいのならplacement newを使ってもいいのでしょうか?
デストラクタについてですがplacement newを使うと静的になるので とすると の宣言したようになり、プログラム終了時までデストラクタが呼ばれなくなるので
自分で呼ぶ必要があるということでいいですか?
アライメントの問題というのがよくわからないのですが、
ダミーコンストラクタによるインスタンス生成時にクラスAの領域が確保されているので
placement newを使っても問題無いように思うのですけど。
placement newを使うとパディングが変わりAのサイズが変わったりするのですか?
また、ヒープから確保するとなると となってしまいますよね。
なので今回はplacement newを教えていただいたのだと思います。
配列を使わないといけないのかということですが、
Aのインスタンスを複数生成し、そのどれかのメンバの値を取り出す、書きこむ
ということをするときに配列でないと
int x,y;
A ai1;
A ai2;
/* ・・・ */
if(x == 1){
ai1.abc = 0;
y = ai1.cint;
}else if(x == 2){
ai2.abc = 0;
y = ai2.cint;
}
配列にすると のようにかけるため配列を選びました。
std::vectorは使ったことがないのですが
配列より不便になるような欠点はないのですか?
できれば、上記の配列の例をstd::vectorにしたものを書いてもらえませんか?
Re: メンバ変数のconst
引数無しでインスタンス生成ができてしまってもプログラムに支障をきたさない設計にすれば問題ないと思います。zxzy さんが書きました: 引数なしコンストラクタを必要としない場合でplacement newを絶対に使い
ダミーコンストラクタで引数なしのコンストラクタでインスタンスが作成
されてもいいのならplacement newを使ってもいいのでしょうか?
えーと、どうやらplacement newをご存じないようなので、簡単に説明します。
placement new(配置new)とは、名の通り静的なメモリ領域にインスタンスを配置します(追記:この場合はという話で、動的なメモリに確保することもできます)。つまるところ、決してインスタンスが静的になるわけではありません。は違います。確保されたメモリ領域の寿命は確かにstaticと同じですが(追記:例の場合は)、そこに配置されたインスタンスの寿命は同じとは限りません。
そうですね・・・例えばAのインスタンスを入れた後、自分でデストラクタと開放処理を行なえば違うAを同じメモリに配置することも可能ということです。
placement newはあくまでも「メモリに配置する」だけなのでデストラクタ(のあとで裏で行なわれているメモリの開放処理)を呼び出す必要が無いのですが、もしデストラクタでA内で動的に確保した領域を開放する処理などがあった場合はデストラクタを呼び出したくなりますよね?また、先ほど言ったように領域を使いまわす際は自分でデストラクタと開放処理を行なわなくてはならないということです。プログラム終了時までデストラクタが呼ばれなくなるので
自分で呼ぶ必要があるということでいいですか?
A内で動的な確保が行なわれておらず、メモリを使いまわすつもりがないのなら呼び出す必要はありません。
「ダミーコンストラクタによるインスタンス生成時にクラスAの領域が確保されているので」が間違いですね。前述のように、既にあるメモリに配置されているだけで、「ダミーコンストラクタによるインスタンス生成時にクラスAの領域は確保されていません」アライメントの問題というのがよくわからないのですが、
ダミーコンストラクタによるインスタンス生成時にクラスAの領域が確保されているので
placement newを使っても問題無いように思うのですけど。
placement newを使うとパディングが変わりAのサイズが変わったりするのですか?
この場合のアラインメントの問題についてですが、私の言った「char[1000]でもいい」というのが間違いです。charの配列として確保された領域にAを配置すると不具合が起きる場合があるらしいです。
そうですね・・・
とりあえず、描き忘れたことをまとめますと、
デメリット
・placement newを使う場合は引数なしでインスタンスが生成されることを認めなくてはならない
メリット
・配置newは早い
・->ではなく.が使える
注意点
・ダミーの初期化では何もしないこと
vectorを使って不便になる欠点はないと思います。配列を使わないといけないのかということですが、
Aのインスタンスを複数生成し、そのどれかのメンバの値を取り出す、書きこむ
ということをするときに配列でないとのようにif文を書く必要があり、int x,y; A ai1; A ai2; /* ・・・ */ if(x == 1){ ai1.abc = 0; y = ai1.cint; }else if(x == 2){ ai2.abc = 0; y = ai2.cint; }
配列にすると のようにかけるため配列を選びました。
std::vectorは使ったことがないのですが
配列より不便になるような欠点はないのですか?
できれば、上記の配列の例をstd::vectorにしたものを書いてもらえませんか?
#include <vector>
int main(){
using namespace std;
int x, y;
vector<A*> Vector; // A型のポインタの動的配列
vector<A*>::iterator Iterator_vector // A型のポインタの動的配列のイテレータ
Vector.push_back( new A );
Vector.push_back( new A );
// ~処理~
Iterator_vector = Vector.begin();
advance( Iterator_vector, x );
(*Iterator_vector)->abc = 0;
y = (*Iterator_vector)->cint;
return 0;
};
最後に編集したユーザー nullptr on 2012年3月08日(木) 11:03 [ 編集 1 回目 ]
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
例えば以下のコードだと、
A():0
A():1
~A():1
と表示されます。
コンストラクタが2回に対してデストラクタは1回です。
コンストラクタとデストラクタが対称性を持って設計されたクラス(デストラクタが呼ばれないと困るクラス)だと問題になります。
しかもデストラクタは一時変数を解体するときに呼ばれたもので実のところプレースメントnewに対応するものではありません。
メモリ領域を使い回すためnewに対してdeleteを徹底すれば意図しない二重解体という不具合に突き当たります。
静的な変数でも解体のタイミングが異なるだけで同様の問題を含みます。
コンストラクタとデストラクタは対称性を持っていると考えるべきものだと思います。
今回引数の無いコンストラクタが空であれば問題にならないとしても、受け入れることで、将来的にこの手の問題に対して鈍感になってしまうかもしれません。
アラインメントや意図しない解体の問題を避けるには、 というふうにメモリを確保してpが指すアドレス境界に対してプレースメントnewを使えば良いと思います。
コンストラクタがメモリを確保するのではありませんし、デストラクタがメモリを解放するのでもありません。
コンストラクタはメモリを初期化するために呼び出されるものです。
メモリの確保自体はクラスでもintでも同じです。
#include <iostream>
struct A {
const int a;
A() : a(0) { std::cout << "A():" << a << std::endl; }
A(int a) : a(a) { std::cout << "A():" << a << std::endl; }
~A() { std::cout << "~A():" << a << std::endl; }
};
int main(void) {
A a[1]; // メモリを確保して引数のないコンストラクタが呼ばれる
new(&a[0]) A(1); // 引数のあるコンストラクタが呼ばれてメモリを上書き
return 0;
} // デストラクタが呼ばれるが…
A():1
~A():1
と表示されます。
コンストラクタが2回に対してデストラクタは1回です。
コンストラクタとデストラクタが対称性を持って設計されたクラス(デストラクタが呼ばれないと困るクラス)だと問題になります。
しかもデストラクタは一時変数を解体するときに呼ばれたもので実のところプレースメントnewに対応するものではありません。
メモリ領域を使い回すためnewに対してdeleteを徹底すれば意図しない二重解体という不具合に突き当たります。
静的な変数でも解体のタイミングが異なるだけで同様の問題を含みます。
コンストラクタとデストラクタは対称性を持っていると考えるべきものだと思います。
今回引数の無いコンストラクタが空であれば問題にならないとしても、受け入れることで、将来的にこの手の問題に対して鈍感になってしまうかもしれません。
アラインメントや意図しない解体の問題を避けるには、 というふうにメモリを確保してpが指すアドレス境界に対してプレースメントnewを使えば良いと思います。
コンストラクタがメモリを確保するのではありませんし、デストラクタがメモリを解放するのでもありません。
コンストラクタはメモリを初期化するために呼び出されるものです。
メモリの確保自体はクラスでもintでも同じです。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
loweさん、 ISLeさん
placement new について説明していただきありがとうございます。
インスタンスが静的になるわけではないということは
のようにplacement newを使う関数を複数呼ぶ場合はどうなるのでしょうか?
A a[3];でplacement new用に確保した領域にplacement newで配置し
その領域を静的にすると、2回目以降のfunction()でA a[3];が来た時staticが
ついていないのでまた、別の場所に確保することになるように思うのですが
staticと同様に2回目以降A a[3];で新たに確保しないようにできているのでしょうか?
アライメントの問題については
メモリを確保するだけでも配置しようとしている型で確保すれば問題ないのですね。
vectorにすることの欠点はないのですか。しかし、やはり配列より複雑で長くなりますね。
それと.ではなく->を使うことになるのですね。
->を使うのなら にしてヒープから確保する方が楽にできる気がします。
vectorがよくわかってないのですが->じゃなく.にする方法あったりはしないですか?
ですが、実装方法の一つとして知っておきたいと思います。
ところで、GRAMさんは「reserveしてpush_backで加えていければ」
と書かれていましたがreserveは使わなくても大丈夫なのでしょうか?
それと
7行目の にセミコロンがないのと
19行目 にセミコロンがあるのは単なるミスですよね?
vectorがある以外コンソールのC++と同じなので
ISLeさん
mallocを使うのですか。
C++だとコンストラクタ、デストラクタがあるnewを使うべきで
mallocは使うべきでないとあちこちで見たのでC++でmallocは
使うことはないと思っていましたがこういうコンストラクタを
必要とせずメモリの確保だけしたいときに使えるのですね。
ありがとうございました。
softya(ソフト屋)さん
やっぱり と書くのは間違いでしたか。
C#で書くときの参考にしたいと思います。ありがとうございました。
placement new について説明していただきありがとうございます。
インスタンスが静的になるわけではないということは
void function(){
A a[3];
new( a + 0 ) A( 10 );
new( a + 1 ) A( 20 );
new( a + 2 ) A( 30 );
/* ... */
}
int main(){
function();
function();
return 0;
}
A a[3];でplacement new用に確保した領域にplacement newで配置し
その領域を静的にすると、2回目以降のfunction()でA a[3];が来た時staticが
ついていないのでまた、別の場所に確保することになるように思うのですが
staticと同様に2回目以降A a[3];で新たに確保しないようにできているのでしょうか?
アライメントの問題については
メモリを確保するだけでも配置しようとしている型で確保すれば問題ないのですね。
vectorにすることの欠点はないのですか。しかし、やはり配列より複雑で長くなりますね。
それと.ではなく->を使うことになるのですね。
->を使うのなら にしてヒープから確保する方が楽にできる気がします。
vectorがよくわかってないのですが->じゃなく.にする方法あったりはしないですか?
ですが、実装方法の一つとして知っておきたいと思います。
ところで、GRAMさんは「reserveしてpush_backで加えていければ」
と書かれていましたがreserveは使わなくても大丈夫なのでしょうか?
それと
7行目の にセミコロンがないのと
19行目 にセミコロンがあるのは単なるミスですよね?
vectorがある以外コンソールのC++と同じなので
ISLeさん
mallocを使うのですか。
C++だとコンストラクタ、デストラクタがあるnewを使うべきで
mallocは使うべきでないとあちこちで見たのでC++でmallocは
使うことはないと思っていましたがこういうコンストラクタを
必要とせずメモリの確保だけしたいときに使えるのですね。
ありがとうございました。
softya(ソフト屋)さん
やっぱり と書くのは間違いでしたか。
C#で書くときの参考にしたいと思います。ありがとうございました。
Re: メンバ変数のconst
自分ならこう書くという書き方を提示します。zxzy さんが書きました:vectorにすることの欠点はないのですか。しかし、やはり配列より複雑で長くなりますね。
それと.ではなく->を使うことになるのですね。
・・・
ところで、GRAMさんは「reserveしてpush_backで加えていければ」
と書かれていましたがreserveは使わなくても大丈夫なのでしょうか?
参考にどうぞ
C++で好きなように書けるような環境だとしたら(そこそこ速いPCで動かして、十分なリソースがあるなら)、
これが最善だと僕は信じています。
#include <iostream>
#include <vector>
using namespace std; //楽します。スミマセンw
class Hoge
{
public:
Hoge( int n)
: num(n)
{
cout << "コンストラクタが呼ばれました。値は" << num << "です" << endl;
}
void ShowNum() const
{
cout << num << endl;
}
private:
const int num;
};
int main()
{
vector< Hoge > arrayHoge; //Hogeクラスを格納するvector
arrayHoge.reserve(5); //vectorに確保されているメモリを最低でも5以上にする
arrayHoge.push_back( Hoge(1) ); //あとは入れていくだけ
arrayHoge.push_back( Hoge(2) );
arrayHoge.push_back( Hoge(3) );
arrayHoge.push_back( Hoge(4) );
arrayHoge.push_back( Hoge(5) );
cout << "-------------------" << endl;
for( int i = 0; i < 5; ++i )
{
arrayHoge[i].ShowNum();
}
}
このコンベンションがややこしくないという理由はいくらでもあります。
①Hogeクラスに何も手を加えない。(空のコンストラクタの制約もない)
②実行結果からわかる通り、引数ありのコンストラクタ呼び出しは1回ですむ。(後述のように、コピーコンストラクタは呼ばれてしまう)
またデフォルトコンストラクタは1度も呼ばれていない。そう。たったの1度も。
③メモリのことを考える必要から解放されている。(reserveで要素数をいれるということを除けば。しかしこれすらも、効率を気にしなければ省ける)
④プレースメントnewという、テクニカルなことをする必要がない。
(ヒープから確保するならなおさらテクニカル。解法や、デストラクタの明示的呼び出し等。またアライメントのことを考える必要も全くない)
⑤この方法ではデストラクタのことを考える必要もない。vectorが破棄されるときに自動で呼ばれる。
⑥そもそも、この方法のデメリットというのがあまり思いつかない。
⑦ただし、あえてデメリットを挙げるとしたら、コピーコンストラクタが必要になる。それを作りたくないなら確かにplacement_newを使うしかないのかもしれない
⑧そもそもこのコードを見て、複雑だと感じるでしょうか?自分はふつうに読めるコードだと思います。
という理由で、あくまで自分ならですが、この方法を使うと思われます。
さて、std::vectorですが、 確保しているメモリが連続していなくてはならなくて
しかも、償却定数時間で後ろに要素を付け加えていくことができるわけですから、
考えうる限りでは、あらかじめ確保しているメモリよりも多くの要素を追加しようとすると、メモリの再確保が行われると考えられます。
これも自分の知る限りはですが、償却定数時間にしようとすると、少なくとも現在の要素のx倍(xはなんでもいいが2が使われるのかな?)
のメモリを確保しなくてはなりません。(そうすることで、要素を無限に加えていったときにメモリの再確保の回数がいずれなくなる。)
となると。です。reserveしなくてもいいのですが、reserveした方が、圧倒的に効率がよくなることがあります。
たとえばこの例だとしても、「仮に」最初にメモリが全く確保されていなければ(これはわからない)
push_backのたびに、1回目(メモリ1確保) 2回目(メモリ2確保) 3回目(メモリ4確保) 4回目( メモリ確保なし) 5回目(メモリ8確保)
・・・となって、4回もメモリの再確保が行われていたとしても文句は言えないわけです。
さて、もっと大きなサイズならどうなるのでしょうね?
・・・という理由でreserveします。
最後にoperator.か->かという話ですが、見ての通りです。vectorは場合によってはoperator[]でアクセスしたほうがいい時もあります。
(ループ途中で要素が追加されるときなど)
iteratorしか使えないわけでもないので、そこらへんはご自由に。(自分は結構使い分ける人ですが)
Re: メンバ変数のconst
プレースメントnewを使うときに変な誤解をするといけないと思って指摘しただけなのに、横道が伸びてしまって申し訳ないです。
つまり宣言しただけでクラスオブジェクトが構築されます。
プレースメントnewはコンストラクタを呼び出して、指定したアドレスを先頭としたメモリを初期化するだけです。
そして初期化によって上書きしてしまうわけですから、既にそこにあったオブジェクトは破壊されます。
一時変数の配列aはfunction関数の終わりでライフサイクルを抜けます。
それと同時にデストラクタが呼び出されクラスオブジェクトが解体されます。
そのあとメモリも解放されます。
破壊されたオブジェクトがライフサイクルを終えて解体されるという状況を、わたしはバグだと思います。
new/deleteだけがコンストラクタ/デストラクタを呼ぶのではありません。
上に書いたように、クラス型の変数を宣言すれば自動的にコンストラクタが呼ばれますし、ライフサイクルを抜けると自動的にデストラクタが呼ばれます。
mallocはどんなオブジェクトに対してもアラインメントの問題が起きないようにアドレス境界を調整してくれます。
一時変数の配列aを宣言することで(これ以前に)確保されたメモリを引数の無いコンストラクタで初期化します。zxzy さんが書きました:A a[3];でplacement new用に確保した領域にplacement newで配置し
その領域を静的にすると、2回目以降のfunction()でA a[3];が来た時staticが
ついていないのでまた、別の場所に確保することになるように思うのですが
staticと同様に2回目以降A a[3];で新たに確保しないようにできているのでしょうか?
つまり宣言しただけでクラスオブジェクトが構築されます。
プレースメントnewはコンストラクタを呼び出して、指定したアドレスを先頭としたメモリを初期化するだけです。
そして初期化によって上書きしてしまうわけですから、既にそこにあったオブジェクトは破壊されます。
一時変数の配列aはfunction関数の終わりでライフサイクルを抜けます。
それと同時にデストラクタが呼び出されクラスオブジェクトが解体されます。
そのあとメモリも解放されます。
破壊されたオブジェクトがライフサイクルを終えて解体されるという状況を、わたしはバグだと思います。
new/deleteは任意のタイミングで構築/解体をするための演算子です。zxzy さんが書きました:mallocを使うのですか。
C++だとコンストラクタ、デストラクタがあるnewを使うべきで
mallocは使うべきでないとあちこちで見たのでC++でmallocは
使うことはないと思っていましたがこういうコンストラクタを
必要とせずメモリの確保だけしたいときに使えるのですね。
new/deleteだけがコンストラクタ/デストラクタを呼ぶのではありません。
上に書いたように、クラス型の変数を宣言すれば自動的にコンストラクタが呼ばれますし、ライフサイクルを抜けると自動的にデストラクタが呼ばれます。
mallocはどんなオブジェクトに対してもアラインメントの問題が起きないようにアドレス境界を調整してくれます。
Re: メンバ変数のconst
はい、確認しないで送信してました、すみませんm(_ _;)m
ああ、zxzy さんが書きました: vectorがよくわかってないのですが->じゃなく.にする方法あったりはしないですか?
#include <vector>
int main(){
using namespace std;
int x, y;
vector<A> Vector; // A型の動的配列
Vector.push_back( A(1) );
Vector.push_back( A(2) );
// ~処理~
Vector[x-1].abc = 0;
y = Vector[x-1].cint;
return 0;
}
GRAMさんがほとんど説明されてますので特に説明はいらないと思いますが、vectorを使えばplacement newよりいいことはたくさんあります。(placement newは実際はどちらかっていうとメモリプールとかに使うテクニックなんで)
/* ここから余談 */
► スポイラーを表示
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: メンバ変数のconst
>ISLeさん
トピックの流れからいうと、無茶苦茶どうでもいいことなんですが、このコードは厳密には規格違反(たぶん、いわゆる「鼻から悪魔」のコード)です。
なぜなら、構造体Aが定数修飾された非静的メンバを持っているからです。メンバ変数a が単なるint型なら全く問題は無いのですが…
#include <iostream>
struct A {
const int a;
A() : a(0) { std::cout << "A():" << a << std::endl; }
A(int a) : a(a) { std::cout << "A():" << a << std::endl; }
~A() { std::cout << "~A():" << a << std::endl; }
};
int main(void) {
A a[1]; // メモリを確保して引数のないコンストラクタが呼ばれる
new(&a[0]) A(1); // 引数のあるコンストラクタが呼ばれてメモリを上書き
return 0;
} // デストラクタが呼ばれるが…
なぜなら、構造体Aが定数修飾された非静的メンバを持っているからです。メンバ変数a が単なるint型なら全く問題は無いのですが…
Re: メンバ変数のconst
GRAMさん、ISLeさん、loweさん返信ありがとうございます。
loweさんのコードで複雑に感じたのはメンバに代入する部分も
書いてもらったためイテレータなども組合わさっていたためですね。
vectorのポインタ イテレータ テンプレートと見慣れないものが
たくさんあったためなので慣れればそうでもないかなと思えました。
placement new や newのほうがテクニカルなのですか。
vectorのほうが高度でテクニカルだと思ってました。
コピーコンストラクタはクラスをコピーするときに使うので、
デフォルト以外を使うなら他の方法でも必要な気がします。
教えていただいたコードにも書かれていなく普通にコピーするだけのときは
書かなくてもいいようですし特にデメリットというほどでもないですね。
丁寧な説明ありがとうございます。
例のプログラムを見たところ[]のほうがわかりやすいなと思えました。
質問してばかりですが毎回丁寧に回答していただきありがたいです。
2回目以降に1回目のfunction関数で変更した値は残っていないんですね。
なら、静的というのはどういうことですか?静的というとプログラムの最後までメモリが確保され
残っているものだと思っていたのですが、これが間違いですか?
placement new自体を使わないほうがいいということでしょうか?
placement newはメモリプールに使うものだったのですか。
調べてみたらVC++とは別にインストールがいるようですね。
便利そうですがC++ですらまだ知らない部分が多く回答いただくたびに知らない用語を
いろいろ調べているレベルなのでboostの導入は今回しないでおきます。
最初の頃beatleさんが代案としてだしてくれたmapの方法にあったboostというものも
これなのですね。みたことがないincludeだなと思っただけで流してしまいましたが。。
少し話がずれますが
GRAMさんが書いてくれたコード
最初見たときVC++を入れてないPCで見たので
Cygwinで実行しようとしました。
すると、エラーが出てコンパイルできませんでした。
いろいろ変えてみたりして
・const int num;をint num;にしたとき
・vector使わずにHoge h(1);としたとき
はコンパイルが通りました。
通ったはいいがダメだった理由はわかりません。
このままだとコンパイルが通らない理由はなんなのでしょう?
VC++でしか使えない書き方ではないと思うのですけど・・・
エラーメッセージは
~/vector.tcc:238: error: non-static const member `const int Hoge::num', can't use default assignment operator
です。
VC++2010を入れている方で後で試したらそのままのコピペで
動作しました。
GRAMさんの書いたコードをみるとそこまで複雑ではないですね。GRAM さんが書きました:
ややこしいという話ですが、自分には到底そうは思えません。
このコンベンションがややこしくないという理由はいくらでもあります。
①Hogeクラスに何も手を加えない。(空のコンストラクタの制約もない)
②実行結果からわかる通り、引数ありのコンストラクタ呼び出しは1回ですむ。(後述のように、コピーコンストラクタは呼ばれてしまう)
またデフォルトコンストラクタは1度も呼ばれていない。そう。たったの1度も。
③メモリのことを考える必要から解放されている。(reserveで要素数をいれるということを除けば。しかしこれすらも、効率を気にしなければ省ける)
④プレースメントnewという、テクニカルなことをする必要がない。
(ヒープから確保するならなおさらテクニカル。解法や、デストラクタの明示的呼び出し等。またアライメントのことを考える必要も全くない)
⑤この方法ではデストラクタのことを考える必要もない。vectorが破棄されるときに自動で呼ばれる。
⑥そもそも、この方法のデメリットというのがあまり思いつかない。
⑦ただし、あえてデメリットを挙げるとしたら、コピーコンストラクタが必要になる。それを作りたくないなら確かにplacement_newを使うしかないのかもしれない
⑧そもそもこのコードを見て、複雑だと感じるでしょうか?自分はふつうに読めるコードだと思います。
loweさんのコードで複雑に感じたのはメンバに代入する部分も
書いてもらったためイテレータなども組合わさっていたためですね。
vectorのポインタ イテレータ テンプレートと見慣れないものが
たくさんあったためなので慣れればそうでもないかなと思えました。
placement new や newのほうがテクニカルなのですか。
vectorのほうが高度でテクニカルだと思ってました。
コピーコンストラクタはクラスをコピーするときに使うので、
デフォルト以外を使うなら他の方法でも必要な気がします。
教えていただいたコードにも書かれていなく普通にコピーするだけのときは
書かなくてもいいようですし特にデメリットというほどでもないですね。
reserveがあったほうがいい理由がわかりました。GRAM さんが書きました: さて、std::vectorですが、 確保しているメモリが連続していなくてはならなくて
しかも、償却定数時間で後ろに要素を付け加えていくことができるわけですから、
考えうる限りでは、あらかじめ確保しているメモリよりも多くの要素を追加しようとすると、メモリの再確保が行われると考えられます。
これも自分の知る限りはですが、償却定数時間にしようとすると、少なくとも現在の要素のx倍(xはなんでもいいが2が使われるのかな?)
のメモリを確保しなくてはなりません。(そうすることで、要素を無限に加えていったときにメモリの再確保の回数がいずれなくなる。)
となると。です。reserveしなくてもいいのですが、reserveした方が、圧倒的に効率がよくなることがあります。
たとえばこの例だとしても、「仮に」最初にメモリが全く確保されていなければ(これはわからない)
push_backのたびに、1回目(メモリ1確保) 2回目(メモリ2確保) 3回目(メモリ4確保) 4回目( メモリ確保なし) 5回目(メモリ8確保)
・・・となって、4回もメモリの再確保が行われていたとしても文句は言えないわけです。
さて、もっと大きなサイズならどうなるのでしょうね?
・・・という理由でreserveします。
丁寧な説明ありがとうございます。
operatorがiteratorのようなものかと思って調べましたが普通に演算子のことなんですね。GRAM さんが書きました: 最後にoperator.か->かという話ですが、見ての通りです。vectorは場合によってはoperator[]でアクセスしたほうがいい時もあります。
(ループ途中で要素が追加されるときなど)
iteratorしか使えないわけでもないので、そこらへんはご自由に。(自分は結構使い分ける人ですが)
例のプログラムを見たところ[]のほうがわかりやすいなと思えました。
いえ、使ったことのないものだったので詳しい説明や注意などを聞けて勉強になります。ISLe さんが書きました:プレースメントnewを使うときに変な誤解をするといけないと思って指摘しただけなのに、横道が伸びてしまって申し訳ないです。
質問してばかりですが毎回丁寧に回答していただきありがたいです。
ということはfunction関数を抜けた時点でplacement newで配置したものはなくなるのでISLe さんが書きました: 一時変数の配列aを宣言することで(これ以前に)確保されたメモリを引数の無いコンストラクタで初期化します。
つまり宣言しただけでクラスオブジェクトが構築されます。
プレースメントnewはコンストラクタを呼び出して、指定したアドレスを先頭としたメモリを初期化するだけです。
そして初期化によって上書きしてしまうわけですから、既にそこにあったオブジェクトは破壊されます。
一時変数の配列aはfunction関数の終わりでライフサイクルを抜けます。
それと同時にデストラクタが呼び出されクラスオブジェクトが解体されます。
そのあとメモリも解放されます。
2回目以降に1回目のfunction関数で変更した値は残っていないんですね。
なら、静的というのはどういうことですか?静的というとプログラムの最後までメモリが確保され
残っているものだと思っていたのですが、これが間違いですか?
placement newを使う以上しょうがないことだと思うのですがISLe さんが書きました: 破壊されたオブジェクトがライフサイクルを終えて解体されるという状況を、わたしはバグだと思います。
placement new自体を使わないほうがいいということでしょうか?
vectorはpush_backで動的に要素を追加していけるのではないのですか?lowe さんが書きました: ああ、みたいにすればできると思いますが・・・ただこれだと動的な確保が面倒になりませんかね?この場合のAがどういう使い方をされるかによりますが#include <vector> int main(){ using namespace std; int x, y; vector<A> Vector; // A型の動的配列 Vector.push_back( A(1) ); Vector.push_back( A(2) ); // ~処理~ Vector[x-1].abc = 0; y = Vector[x-1].cint; return 0; }
GRAMさんがほとんど説明されてますので特に説明はいらないと思いますが、vectorを使えばplacement newよりいいことはたくさんあります。(placement newは実際はどちらかっていうとメモリプールとかに使うテクニックなんで)
placement newはメモリプールに使うものだったのですか。
vectorは名前は聞いたことがあったのですがboostは全く聞いたことがありませんでした。lowe さんが書きました: boostライブラリにptr_vectorなんてものがあります。
かなり便利なんで私も多用しちゃってるんですが、、、
それを使うとこんな感じになります。これを使えば.演算子でアクセスできますし(イテレータでもoperator[]を使った場合でも)、要素を消すときにいちいちdeleteを呼ぶ必要もなく、newでつっこめるんで動的確保も楽です。#include <boost/ptr_container/ptr_vector.hpp> int main(){ using namespace std; int x, y; boost::ptr_vector<A> Vector; // A型の「ポインタの」動的配列 Vector.push_back( new A(1) ); // ポインタを入れる Vector.push_back( new A(2) ); // ~処理~ Vector[x-1].abc = 0; // .演算子でアクセスできる y = Vector[x-1].cint; return 0; }
・・・まぁboostを導入しなくちゃいけなかったり若干注意しなくてはならない点もあったりするんでvectorを知らないならオススメはしませんが、参考までに。
調べてみたらVC++とは別にインストールがいるようですね。
便利そうですがC++ですらまだ知らない部分が多く回答いただくたびに知らない用語を
いろいろ調べているレベルなのでboostの導入は今回しないでおきます。
最初の頃beatleさんが代案としてだしてくれたmapの方法にあったboostというものも
これなのですね。みたことがないincludeだなと思っただけで流してしまいましたが。。
少し話がずれますが
GRAMさんが書いてくれたコード
これの実行結果をみようと実行しようとしたのですがGRAM さんが書きました:#include <iostream> #include <vector> using namespace std; //楽します。スミマセンw class Hoge { public: Hoge( int n) : num(n) { cout << "コンストラクタが呼ばれました。値は" << num << "です" << endl; } void ShowNum() const { cout << num << endl; } private: const int num; }; int main() { vector< Hoge > arrayHoge; //Hogeクラスを格納するvector arrayHoge.reserve(5); //vectorに確保されているメモリを最低でも5以上にする arrayHoge.push_back( Hoge(1) ); //あとは入れていくだけ arrayHoge.push_back( Hoge(2) ); arrayHoge.push_back( Hoge(3) ); arrayHoge.push_back( Hoge(4) ); arrayHoge.push_back( Hoge(5) ); cout << "-------------------" << endl; for( int i = 0; i < 5; ++i ) { arrayHoge[i].ShowNum(); } }
最初見たときVC++を入れてないPCで見たので
Cygwinで実行しようとしました。
すると、エラーが出てコンパイルできませんでした。
いろいろ変えてみたりして
・const int num;をint num;にしたとき
・vector使わずにHoge h(1);としたとき
はコンパイルが通りました。
通ったはいいがダメだった理由はわかりません。
このままだとコンパイルが通らない理由はなんなのでしょう?
VC++でしか使えない書き方ではないと思うのですけど・・・
エラーメッセージは
~/vector.tcc:238: error: non-static const member `const int Hoge::num', can't use default assignment operator
です。
VC++2010を入れている方で後で試したらそのままのコピペで
動作しました。
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: メンバ変数のconst
「std::vector::push_back関数が内部で代入演算子を使っているのに、適切な代入演算子が定義されていない」という意味のエラーですが、Hoge::numがconstなので、自明な代入演算子(要するに、メンバ変数の一つ一つにコピー演算子を適用していく代入演算子のこと。必要に応じてコンパイラが自動でメンバに加える。)が定義できないから起こっているのです。zxzy さんが書きました: ~/vector.tcc:238: error: non-static const member `const int Hoge::num', can't use default assignment operator
ところが、適切な代入演算子を定義する方法が今回はありません。だから、Hogeをコンテナに入れることは実はあまりお勧めできません。どうがんばっても、Hogeをコンテナの要素としての要件を満たすように代入演算子を定義できませんから…
Re: メンバ変数のconst
class Hoge
{
public:
Hoge( int n)
: num(n)
{
cout << "コンストラクタが呼ばれました。値は" << num << "です" << endl;
}
void ShowNum() const
{
cout << num << endl;
}
// コンパイラが生成するデフォルトの代入演算子
Hoge &operator=(const Hoge &other)
{
// num は const なので代入できない
num = other.num;
return *this;
}
private:
const int num;
};
代入演算子を省略した場合に、コンパイラが自動で生成する代入演算子は、
すべてのメンバーを一つずつ代入するので、エラーとなります。
VC++ の場合は、reserve や push_back が Hoge::operator= をたまたま使わないので、
Hoge::operator= が無視されていると考えられます。
Hoge::operator= が num を変更しない代入演算を行えば、コンパイルできますが、
それが、正しい実装であるかは、Hoge の設計者がよく考える必要があります。
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: メンバ変数のconst
それに加えて、ユーザー定義の型TをC++の標準コンテナに入れる場合、コピーコンストラクタと代入演算子の適用後、元のオブジェクトとの等値であるように(要するに、operator==で比較したときに真になるように)コピーコンストラクタと代入演算子を定義しないと、コンテナ自体がおかしくなる場合があります。a5ua さんが書きました:std::vector<T> における T は、コピーコンストラクタと代入演算子を持っていなければいけません。
要するに、intやポインタ型のような型とできる限り同じように振舞うようにするのが、コンテナの要素としては理想の型であるということです。
ところが、今回のHoge型は、constなメンバを持っている為に、それを満たすように代入演算子が定義できないのですね。const修飾を無理やり外すと確実に未定義になりますからね…
Re: メンバ変数のconst
オブジェクトの構築・解体において定値(const)修飾に関して未定義の動作になるのは、tkmakwins15 さんが書きました:>ISLeさんトピックの流れからいうと、無茶苦茶どうでもいいことなんですが、このコードは厳密には規格違反(たぶん、いわゆる「鼻から悪魔」のコード)です。#include <iostream> struct A { const int a; A() : a(0) { std::cout << "A():" << a << std::endl; } A(int a) : a(a) { std::cout << "A():" << a << std::endl; } ~A() { std::cout << "~A():" << a << std::endl; } }; int main(void) { A a[1]; // メモリを確保して引数のないコンストラクタが呼ばれる new(&a[0]) A(1); // 引数のあるコンストラクタが呼ばれてメモリを上書き return 0; } // デストラクタが呼ばれるが…
なぜなら、構造体Aが定数修飾された非静的メンバを持っているからです。メンバ変数a が単なるint型なら全く問題は無いのですが…
- 定値オブジェクトが占有する領域を再使用する場合(メンバについては記述無し)
- 定値修飾された非静的メンバを含むオブジェクトを再使用したとき、再使用する前に指していたポインタ・参照・名前を使ってアクセスした場合
生存期間終わりの自動解体に関しては解体時に同じ型のオブジェクトであることを保証できなければ未定義となってます。
文面通りに解釈すれば未定義になるコードは含まれていないと言える気がするのですけど。
constを剥がして書き換えるのは未定義ですけど、ここでは関係無いと思います。
規格の話になったので補足しておきますけど、
プレースメントnewを使ってコンストラクタとデストラクタの数が合わなくなっても規格上は違反ではないのです。
規格に、再使用するときにデストラクタを明示的に呼び出さなくても良いがその場合デストラクタの副作用に依存したプログラムの動作は未定義、なんてふうに書かれているのですが、現実的な話としてデストラクタに副作用が無いと考えてコード書くのは良くないと思います。
Re: メンバ変数のconst
プレースメントnewで使用しているメモリはあくまでも関数内で宣言された一時変数に割り当てられたものですからね。zxzy さんが書きました:ということはfunction関数を抜けた時点でplacement newで配置したものはなくなるので
2回目以降に1回目のfunction関数で変更した値は残っていないんですね。
なら、静的というのはどういうことですか?静的というとプログラムの最後までメモリが確保され
残っているものだと思っていたのですが、これが間違いですか?
わたしは「静的」という単語は「静的な変数の生存範囲」のときにしか使ってないのですけど。
スレを読み直してみたところloweさんが「プレースメントnewは静的に配置される」と書かれてました。
これは間違いですね。
プレースメントnewは指定されたアドレスに上書きするだけですから動的に確保されたメモリにも使えます。
プレースメントnewを使うとメモリが再割当てされるわけではありません。
プレースメントnewで指定したアドレスのメモリ領域はそれが割り当てられた元のオブジェクトの生存期間に準じます。
規格上は違反ではないので分かってて使う分には良いのですけどね。zxzy さんが書きました:placement newを使う以上しょうがないことだと思うのですがISLe さんが書きました:破壊されたオブジェクトがライフサイクルを終えて解体されるという状況を、わたしはバグだと思います。
placement new自体を使わないほうがいいということでしょうか?
厳しい条件を忘れてうっかりバグを埋め込んでしまわないようになるべく使わないほうが良いと思います。
たいてい他にもっと良い方法があるはずです。
プレースメントnewを使うのはメモリプールを実装するときだけにしておいてください。
Re: メンバ変数のconst
わたしがあげた例の話として「静的なメモリ領域にインスタンスを配置します」と言ったつもりでして、決して静的でなくてはならないと言ったつもりは無いのですが・・・・・。ISLe さんが書きました: スレを読み直してみたところloweさんが「プレースメントnewは静的に配置される」と書かれてました。
これは間違いですね。
まぁいずれにせよ誤解を招いたのは私の非ですね、zxzyさんすみませんでしたm(_ _)m
【追記】
すごく今更ですがそれらのところに動的な領域でもいい旨を書きました
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: メンバ変数のconst
>>tkmakwins15さん、a5ua さん、ISLeさん
ご指摘ありがとうございます。誠おっしゃる通りです。
そしてzxzyさん。謝ります。本当にすみませんm(_ _)m
忘れてください!!
これならいけるんじゃね?とおもってVC++で動いたときは、これでいいや。と思ったんですが、
あろうことか、基本的な要件を満たせていないのですね。やれやれ。
あやうくzxzyさんを未定義の闇に引きずり込むところでした。
しかし結局特にこれといった注意を払わなくてよくて、安全で
かつzxzyさんの要件を満たすような魔法の方法はないのでしょうかね?
(なんか自分が勉強不足なだけで古今東西議論されつくしてそうな話題な気もしますが。)
ご指摘ありがとうございます。誠おっしゃる通りです。
そしてzxzyさん。謝ります。本当にすみませんm(_ _)m
忘れてください!!
これならいけるんじゃね?とおもってVC++で動いたときは、これでいいや。と思ったんですが、
あろうことか、基本的な要件を満たせていないのですね。やれやれ。
あやうくzxzyさんを未定義の闇に引きずり込むところでした。
しかし結局特にこれといった注意を払わなくてよくて、安全で
かつzxzyさんの要件を満たすような魔法の方法はないのでしょうかね?
(なんか自分が勉強不足なだけで古今東西議論されつくしてそうな話題な気もしますが。)
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: メンバ変数のconst
>ISLeさん
申し訳ありません、確かに、constメンバを含むクラスにプレースメントnewを用いても、それだけでは未定義の操作になるわけではないですね。
プレースメントnewした後でa[0]にアクセスしたらアウトでしょうけれども…
>GRAMさん
考えて見ましたが、そもそもzxzyさんのやろうとしていること自体がかなりイレギュラーです。constメンバを変数初期化後に変更しようということ自体が認められていませんし、プレースメントnewにしても、ISLeさんが提示したコード以上のことをやってしまうと、未定義のコードになっちゃいますし…
単にconstメンバを含むクラスを配列にしたいというだけならば、そもそもsoftya(ソフト屋)さんの提示したコードで解決していますし… intで宣言した変数をconst intに書き換えるのは絶対に不可能ですからね…
申し訳ありません、確かに、constメンバを含むクラスにプレースメントnewを用いても、それだけでは未定義の操作になるわけではないですね。
プレースメントnewした後でa[0]にアクセスしたらアウトでしょうけれども…
>GRAMさん
考えて見ましたが、そもそもzxzyさんのやろうとしていること自体がかなりイレギュラーです。constメンバを変数初期化後に変更しようということ自体が認められていませんし、プレースメントnewにしても、ISLeさんが提示したコード以上のことをやってしまうと、未定義のコードになっちゃいますし…
単にconstメンバを含むクラスを配列にしたいというだけならば、そもそもsoftya(ソフト屋)さんの提示したコードで解決していますし… intで宣言した変数をconst intに書き換えるのは絶対に不可能ですからね…
Re: メンバ変数のconst
返信ありがとうございます。
うぅ..C++って難しいですね。
なんか嫌になってきます…
コンパイルエラーに関して
VC++で=をたまたま使わないからだったのですか。
それに比べるとCygwinは使わなくてもチェックしてくれるんですね。
VC++で を試してみたらちゃんとコンパイル時にエラーを確認できました。
vectorの場合は追加時にメモリが足りないと別の場所に確保してコピーするようなので
この方法は使わないほうがいいみたいですね。
a5uaさん
コンパイラが生成するデフォルトの代入演算子ってこんなのなんですね。
プレースメントnewに関して
ISLeさん丁寧な解説ありがとうございます。
staticがなくA a[10];だけだったので宣言がローカルでもなんでも静的になるのだと勝手に解釈していました。
こちらこそ理解力なくてすみません。
でも、いい方法ってこれくらいしかないのですかね。(mapとptr_vectorもコンテナはダメみたいですし)
今回するつもりのことでは使いませんがsoftya(ソフト屋)さんのコードでもconstを使っている以上コピーは
できませんよね。
もうconstなんて使わずただのintにして自分で値を変更しないよう注意すればいいかなとも思えてきました…
メンバ変数に定数を使いたいことってよくあるような気がするのですがそんなイレギュラーだったのですか?
あと、
ないのですか?a[0]にアクセスして未定義になるなら配置したものにアクセスできないし、
こちらに書かれているコードで でプレースメントnewのあとにsample.getNum()のアクセスもダメということになるのではないのでしょうか?
うぅ..C++って難しいですね。
なんか嫌になってきます…
コンパイルエラーに関して
VC++で=をたまたま使わないからだったのですか。
それに比べるとCygwinは使わなくてもチェックしてくれるんですね。
VC++で を試してみたらちゃんとコンパイル時にエラーを確認できました。
vectorの場合は追加時にメモリが足りないと別の場所に確保してコピーするようなので
この方法は使わないほうがいいみたいですね。
a5uaさん
コンパイラが生成するデフォルトの代入演算子ってこんなのなんですね。
プレースメントnewに関して
ISLeさん丁寧な解説ありがとうございます。
書いていただいたコードのAのメモリを確保するときにlowe さんが書きました:わたしがあげた例の話として「静的なメモリ領域にインスタンスを配置します」と言ったつもりでして、決して静的でなくてはならないと言ったつもりは無いのですが・・・・・。ISLe さんが書きました:スレを読み直してみたところloweさんが「プレースメントnewは静的に配置される」と書かれてました。
これは間違いですね。
まぁいずれにせよ誤解を招いたのは私の非ですね、zxzyさんすみませんでしたm(_ _)m
staticがなくA a[10];だけだったので宣言がローカルでもなんでも静的になるのだと勝手に解釈していました。
こちらこそ理解力なくてすみません。
そうですね。今回はプレースメントnewを使うのはやめておきます。ISLe さんが書きました: 規格上は違反ではないので分かってて使う分には良いのですけどね。
厳しい条件を忘れてうっかりバグを埋め込んでしまわないようになるべく使わないほうが良いと思います。
たいてい他にもっと良い方法があるはずです。
プレースメントnewを使うのはメモリプールを実装するときだけにしておいてください。
GRAM さんが書きました: しかし結局特にこれといった注意を払わなくてよくて、安全で
かつzxzyさんの要件を満たすような魔法の方法はないのでしょうかね?
softya(ソフト屋)さんに教えていただいたコードでやりたいことはできているのでこれでいこうかなと思います。tkmakwins15 さんが書きました: 考えて見ましたが、そもそもzxzyさんのやろうとしていること自体がかなりイレギュラーです。constメンバを変数初期化後に変更しようということ自体が認められていませんし、プレースメントnewにしても、ISLeさんが提示したコード以上のことをやってしまうと、未定義のコードになっちゃいますし…
単にconstメンバを含むクラスを配列にしたいというだけならば、そもそもsoftya(ソフト屋)さんの提示したコードで解決していますし… intで宣言した変数をconst intに書き換えるのは絶対に不可能ですからね…
でも、いい方法ってこれくらいしかないのですかね。(mapとptr_vectorもコンテナはダメみたいですし)
今回するつもりのことでは使いませんがsoftya(ソフト屋)さんのコードでもconstを使っている以上コピーは
できませんよね。
もうconstなんて使わずただのintにして自分で値を変更しないよう注意すればいいかなとも思えてきました…
メンバ変数に定数を使いたいことってよくあるような気がするのですがそんなイレギュラーだったのですか?
あと、
をみて思ったのですがプレースメントnewをするとa[0]って配置されたものにアクセスすることになるのではtkmakwins15 さんが書きました: プレースメントnewした後でa[0]にアクセスしたらアウトでしょうけれども…
ないのですか?a[0]にアクセスして未定義になるなら配置したものにアクセスできないし、
こちらに書かれているコードで でプレースメントnewのあとにsample.getNum()のアクセスもダメということになるのではないのでしょうか?
Re: メンバ変数のconst
未定義の動作になるのは、定値修飾された非静的(constありstaticなし)メンバを含む場合です。zxzy さんが書きました:をみて思ったのですがプレースメントnewをするとa[0]って配置されたものにアクセスすることになるのではtkmakwins15 さんが書きました: プレースメントnewした後でa[0]にアクセスしたらアウトでしょうけれども…
ないのですか?a[0]にアクセスして未定義になるなら配置したものにアクセスできないし、
こちらに書かれているコードで でプレースメントnewのあとにsample.getNum()のアクセスもダメということになるのではないのでしょうか?
#他にも条件があります。
tkmakwins15 さんの日記のコードは未定義の動作にならない条件を満たしているので問題ないです。
プレースメントnewの戻り値を使えば再使用された新しいオブジェクトに正しくアクセスできます。
#include <iostream>
struct A {
const int a; // 定値修飾された非静的メンバ
A() : a(0) { std::cout << "A():" << a << std::endl; }
A(int a) : a(a) { std::cout << "A():" << a << std::endl; }
~A() { std::cout << "~A():" << a << std::endl; }
};
int main(void) {
A a[1];
A *p = new(&a[0]) A(1); // 再使用される直前にa[0]の生存範囲は終了したとみなせる
a[0].a; // a[0]は無効 未定義の動作
p->a; // OK
return 0;
}
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: メンバ変数のconst
「メンバ変数にconstをつけること」ではなくて、「それをコンストラクタの初期化子以外で初期化しようとすること」がイレギュラーということですね。zxzy さんが書きました:メンバ変数に定数を使いたいことってよくあるような気がするのですがそんなイレギュラーだったのですか?
初期化以降のコードでconst変数を書き換えると、そもそもconstの意味が分からなくなりますからね。
Re: メンバ変数のconst
返信ありがとうございます。
constありなら返り値を使う必要があるんですね。
ということはプレースメントnewでもアクセスは->になりますね。
でも、どうしてconstありstaticなしのメンバがあると未定義になるのでしょうか?
constをはずすわけではないしintならよくてconst intになるとダメになる理由がわからないです。
constが最初の一回だけ初期化or代入ができるというふうになっていれば使いやすいんですけどね。
よくみるとconstがついてないですね。ISLe さんが書きました: 未定義の動作になるのは、定値修飾された非静的(constありstaticなし)メンバを含む場合です。
#他にも条件があります。
tkmakwins15 さんの日記のコードは未定義の動作にならない条件を満たしているので問題ないです。
プレースメントnewの戻り値を使えば再使用された新しいオブジェクトに正しくアクセスできます。未定義の動作というのはたまたま動いてしまう場合も含まれるので気を付けましょう。#include <iostream> struct A { const int a; // 定値修飾された非静的メンバ A() : a(0) { std::cout << "A():" << a << std::endl; } A(int a) : a(a) { std::cout << "A():" << a << std::endl; } ~A() { std::cout << "~A():" << a << std::endl; } }; int main(void) { A a[1]; A *p = new(&a[0]) A(1); // 再使用される直前にa[0]の生存範囲は終了したとみなせる a[0].a; // a[0]は無効 未定義の動作 p->a; // OK return 0; }
constありなら返り値を使う必要があるんですね。
ということはプレースメントnewでもアクセスは->になりますね。
でも、どうしてconstありstaticなしのメンバがあると未定義になるのでしょうか?
constをはずすわけではないしintならよくてconst intになるとダメになる理由がわからないです。
普通に初期化子で初期化する softya(ソフト屋) さんに教えていただいた方法をとることにします。tkmakwins15 さんが書きました: 「メンバ変数にconstをつけること」ではなくて、「それをコンストラクタの初期化子以外で初期化しようとすること」がイレギュラーということですね。
初期化以降のコードでconst変数を書き換えると、そもそもconstの意味が分からなくなりますからね。
constが最初の一回だけ初期化or代入ができるというふうになっていれば使いやすいんですけどね。
Re: メンバ変数のconst
new演算子の戻り値を必ず使うということで良いのではないでしょうかね。zxzy さんが書きました:constありなら返り値を使う必要があるんですね。
ということはプレースメントnewでもアクセスは->になりますね。
ポインタと配列は文法上は互換なので->を使う代わりに
p[0].a
と書くこともできますが…。
アロー演算子(->)が使ってあると、このオブジェクトは移動や複写しないように設計されているのだな、というのがその場で分かります。
ドット演算子(.)が使われているとコードをさかのぼらないとポインタなのか配列なのか区別できないのでコードを読むのに手間がかかります。
JavaとかC#とかはドット演算子しかないですけど、クラス型に対してはアロー演算子と同じ作用しかしませんからその場で判断できます。
読みやすいコードというのはコメントの位置とか見た目が揃ってるということではないのですよね。
規格にそう書いてあるから、というのが利用する側の立場ですが、C/C++の規格は既存のコンパイラの実装に配慮した内容があちこちにあります。zxzy さんが書きました:でも、どうしてconstありstaticなしのメンバがあると未定義になるのでしょうか?
constをはずすわけではないしintならよくてconst intになるとダメになる理由がわからないです。
想像でしかありませんけど、初期化しかできない定値オブジェクトは最適化の影響でメモリ領域の再使用には収まらない可能性があるのではないでしょうかね。
そういう意味ではconst外しも同様の理由によるかと思います。
staticが付いたメンバは静的に割り当てられるので、メモリの再使用の影響を受けません。
他の言語ではそういうことができますけど、その代わりに犠牲にしていることもあります。zxzy さんが書きました:constが最初の一回だけ初期化or代入ができるというふうになっていれば使いやすいんですけどね。
C/C++は安全性を犠牲にしてでも手に入れたいものがあるひとが使う言語だと思います。
最近はそうでもなくなってきてますけど。
Re: メンバ変数のconst
そうですね。ISLe さんが書きました: new演算子の戻り値を必ず使うということで良いのではないでしょうかね。
いつもそうしていればconstがあるからとか考えなくて済みますしね。
そういえばそんなこともできましたね。ISLe さんが書きました: ポインタと配列は文法上は互換なので->を使う代わりに
p[0].a
と書くこともできますが…。
しかし、そのような書き方だと配列なのかポインタなのかが
わかりづらくなるのでポインタならアロー演算子にします。
.のほうが見やすく書くのが楽と思っていましたが->を使ったほうがいいこともあるのですね。ISLe さんが書きました: アロー演算子(->)が使ってあると、このオブジェクトは移動や複写しないように設計されているのだな、というのがその場で分かります。
ドット演算子(.)が使われているとコードをさかのぼらないとポインタなのか配列なのか区別できないのでコードを読むのに手間がかかります。
JavaとかC#とかはドット演算子しかないですけど、クラス型に対してはアロー演算子と同じ作用しかしませんからその場で判断できます。
読みやすいコードというのはコメントの位置とか見た目が揃ってるということではないのですよね。
JavaやC#にアロー演算子がないのは知りませんでした。
ポインタ使わないようなとても簡単なものしか作ったことがなかったので…
そこはもう規格に書かれていることなのですか。ISLe さんが書きました: 規格にそう書いてあるから、というのが利用する側の立場ですが、C/C++の規格は既存のコンパイラの実装に配慮した内容があちこちにあります。
想像でしかありませんけど、初期化しかできない定値オブジェクトは最適化の影響でメモリ領域の再使用には収まらない可能性があるのではないでしょうかね。
そういう意味ではconst外しも同様の理由によるかと思います。
staticが付いたメンバは静的に割り当てられるので、メモリの再使用の影響を受けません。
規格ってちゃんと読んでおくべきものなんでしょうか?
今まで必要なものの使いかただけ調べて使っていたので規格というのをよんだことないがないです。
もし読むべきであるというのでしたら見やすくまとめられたページ(日本語でお願いします)を
教えてもらえますか?
最適化の影響 ですか。そう考えるとなんか納得できたような気がします。
プログラムの基本的な言語はCかなと思ってほぼC系(C,C++,C#)しか使えないのですがISLe さんが書きました: 他の言語ではそういうことができますけど、その代わりに犠牲にしていることもあります。
C/C++は安全性を犠牲にしてでも手に入れたいものがあるひとが使う言語だと思います。
最近はそうでもなくなってきてますけど。
やっぱり複数の言語が使えてそのときの目的にあったものを使うという風にできたほうがいいですね。
ここの掲示板の過去ログを見ていてもいろいろな言語を使える人が多いと感じますし。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
ちゃんとした規格の日本語というとコレでしょう。
オンライン閲覧のみ可能。
「日本工業標準調査会:データベース-JIS詳細表示」
http://www.jisc.go.jp/app/pager?%23jps. ... ISNO=X3014
[補足]C++11は、まだJIS規格になっていません。
オンライン閲覧のみ可能。
「日本工業標準調査会:データベース-JIS詳細表示」
http://www.jisc.go.jp/app/pager?%23jps. ... ISNO=X3014
[補足]C++11は、まだJIS規格になっていません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
softya(ソフト屋)さん
教えていただきありがとうございます。
C++11はないのかを聞こうとしたら補足が増えてました。
まだ、できていないのですね。
教えていただいたページなのですが、正誤表は正しく表示できるのですが
規格のほうが表示できません。
Google Chromeで開くと読み込み完了しても白紙になってそのまま10分
程度待っても表示されません。スクロールしてみると、ダウンロードしたものは
表示できないみたいなメッセージボックスが出ます。
FireFoxAuroraとIE7ではファイルが壊れているとメッセージが出ます。
softya(ソフト屋)さんのPCでは正しく表示されていますか?
教えていただきありがとうございます。
C++11はないのかを聞こうとしたら補足が増えてました。
まだ、できていないのですね。
教えていただいたページなのですが、正誤表は正しく表示できるのですが
規格のほうが表示できません。
Google Chromeで開くと読み込み完了しても白紙になってそのまま10分
程度待っても表示されません。スクロールしてみると、ダウンロードしたものは
表示できないみたいなメッセージボックスが出ます。
FireFoxAuroraとIE7ではファイルが壊れているとメッセージが出ます。
softya(ソフト屋)さんのPCでは正しく表示されていますか?
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: メンバ変数のconst
私は都合でAdobeReader9を使っていますので残念ながら読めません。
最新のAdobeReaderXを使ってみて下さい。
最新のAdobeReaderXを使ってみて下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: メンバ変数のconst
Windows XP + IE8 + Adobe Reader 9
Windows 7 x64 + IE9 + Adobe Reader X
の組み合わせで表示できてます。
それと環境設定の『インターネット』→Webブラウザオプションの『PDFをブラウザに表示』にチェックが入っていないと表示されません。
ファイルが壊れているとのメッセージはこちらでも出ます。
もう一度リンクをクリックすれば表示されないでしょうか。
Windows 7 x64 + IE9 + Adobe Reader X
の組み合わせで表示できてます。
それと環境設定の『インターネット』→Webブラウザオプションの『PDFをブラウザに表示』にチェックが入っていないと表示されません。
ファイルが壊れているとのメッセージはこちらでも出ます。
もう一度リンクをクリックすれば表示されないでしょうか。
Re: メンバ変数のconst
softya(ソフト屋)さん、ISLeさん返信ありがとうございます。
Adobe Reader 9を使っていたのでアップデートしたところ9の最新版9.5になりました。
Adobe Reader 9内からアップデートではXにはならないのですね。
ISLeさんの書き込みをみて、9でも最新版ならできるかと思い、もう一度IEでやってみたところ
ちゃんと表示ができました。
規格というのは思ってたとおりすごく長く、内容は思っていたのとは違った感じでした。
時間のあるときに少しずつ読んでみようと思います。
ありがとうございました。
これで疑問もすべて解決できたので二度目ですが解決済みとしたいと思います。
質問に答えてくれたみなさん本当にありがとうございました。
Adobe Reader 9を使っていたのでアップデートしたところ9の最新版9.5になりました。
Adobe Reader 9内からアップデートではXにはならないのですね。
ISLeさんの書き込みをみて、9でも最新版ならできるかと思い、もう一度IEでやってみたところ
ちゃんと表示ができました。
規格というのは思ってたとおりすごく長く、内容は思っていたのとは違った感じでした。
時間のあるときに少しずつ読んでみようと思います。
ありがとうございました。
これで疑問もすべて解決できたので二度目ですが解決済みとしたいと思います。
質問に答えてくれたみなさん本当にありがとうございました。